pax_global_header00006660000000000000000000000064133154561620014520gustar00rootroot0000000000000052 comment=9a4265a1c6aac2f8592c88823f3151274e7f1ceb pmdk-1.4.1/000077500000000000000000000000001331545616200124565ustar00rootroot00000000000000pmdk-1.4.1/.codecov.yml000066400000000000000000000004221331545616200146770ustar00rootroot00000000000000ignore: - src/jemalloc/ - src/windows/ - src/test/ - src/common/valgrind/ comment: layout: "diff" behavior: default require_changes: yes parsers: gcov: branch_detection: conditional: false loop: false method: false macro: false pmdk-1.4.1/.gitattributes000066400000000000000000000001711331545616200153500ustar00rootroot00000000000000* text=auto eol=lf *.jpg binary *.png binary *.gif binary *.ico binary *.match text -whitespace GIT_VERSION export-subst pmdk-1.4.1/.gitignore000066400000000000000000000003461331545616200144510ustar00rootroot00000000000000.* !.gitignore !.gitattributes !.clang-format !.travis.yml !.mailmap !.cstyleignore !.codecov.yml *~ *.swp *.o make.out core a.out nbproject/ /rpmbuild/ /dpkgbuild/ /rpm/ /dpkg/ /user.mk *.user ~* *.db *.htmp *.hpptmp *.aps tags pmdk-1.4.1/.mailmap000066400000000000000000000013201331545616200140730ustar00rootroot00000000000000Gábor Buella Hu Wan Igor Chorążewicz Jacob Chang Jan M Michalski Krzysztof Czuryło Łukasz Godlewski Łukasz Plewa Maciej Ramotowski Paul Luse Paweł Lebioda Piotr Balcer Sławomir Pawłowski Tomasz Kapela Weronika Lewandowska Weronika Lewandowska Wojciech Uss pmdk-1.4.1/.travis.yml000066400000000000000000000027641331545616200146000ustar00rootroot00000000000000dist: trusty # use temporarily the previous version of Trusty image # until Travis fixes issue with mounting permissions group: deprecated-2017Q2 sudo: required language: c services: - docker env: global: - OS=ubuntu - OS_VER=16.04 - MAKE_PKG=0 - PMDK_CC=gcc - PMDK_CXX=g++ - REMOTE_TESTS=1 - VALGRIND=1 - LIBCPP_LIBDIR=/usr/local/libcxx/lib - LIBCPP_INCDIR=/usr/local/libcxx/include/c++/v1 - NDCTL_ENABLE=y matrix: - COVERAGE=1 TEST_BUILD=debug - TEST_BUILD=debug - TEST_BUILD=nondebug - PMDK_CC=clang PMDK_CXX=clang++ USE_LLVM_LIBCPP=1 TEST_BUILD=debug - PMDK_CC=clang PMDK_CXX=clang++ USE_LLVM_LIBCPP=1 TEST_BUILD=nondebug - OS=fedora OS_VER=25 PMDK_CC=clang PMDK_CXX=clang++ USE_LLVM_LIBCPP=1 TEST_BUILD=debug - OS=fedora OS_VER=25 PMDK_CC=clang PMDK_CXX=clang++ USE_LLVM_LIBCPP=1 TEST_BUILD=nondebug - MAKE_PKG=1 EXPERIMENTAL=y REMOTE_TESTS=0 VALGRIND=0 NDCTL_ENABLE=n - MAKE_PKG=1 EXPERIMENTAL=y REMOTE_TESTS=0 VALGRIND=0 NDCTL_ENABLE=n PMDK_CC=clang PMDK_CXX=clang++ - MAKE_PKG=1 EXPERIMENTAL=y REMOTE_TESTS=0 VALGRIND=0 NDCTL_ENABLE=y OS=fedora OS_VER=25 - COVERITY=1 before_install: - echo $TRAVIS_COMMIT_RANGE - export HOST_WORKDIR=`pwd` - cd utils/docker - ./pull-or-rebuild-image.sh - if [[ -f push_image_to_repo_flag ]]; then PUSH_THE_IMAGE=1; fi - rm -f push_image_to_repo_flag script: - ./build-travis.sh after_success: - if [[ $PUSH_THE_IMAGE -eq 1 ]]; then images/push-image.sh $OS-$OS_VER; fi pmdk-1.4.1/CODING_STYLE.md000066400000000000000000000163051331545616200147300ustar00rootroot00000000000000# C Style and Coding Standards for Persistent Memory Development Kit This document defines the coding standards and conventions for writing PMDK code. To ensure readability and consistency within the code, the contributed code must adhere to the rules below. ### Introduction The Persistent Memory Development Kit coding style is quite similar to the style used for the SunOS product. A full description of that standard can be found [here.](https://www.cis.upenn.edu/~lee/06cse480/data/cstyle.ms.pdf) This document does not cover the entire set of recommendations and formatting rules used in writing PMDK code, but rather focuses on some PMDK-specific conventions, not described in the document mentioned above, as well as the ones the violation of which is most frequently observed during the code review. Also, keep in mind that more important than the particular style is **consistency** of coding style. So, when modifying the existing code, the changes should be coded in the same style as the file being modified. ### Code formatting Most of the common stylistic errors can be detected by the [style checker program](https://github.com/pmem/pmdk/blob/master/utils/cstyle) included in the repo. Simply run `make cstyle` or `CSTYLE.ps1` to verify if your code is well-formatted. Here is the list of the most important rules: - The limit of line length is 80 characters. - Indent the code with TABs, not spaces. Tab width is 8 characters. - Do not break user-visible strings (even when they are longer than 80 characters) - Put each variable declaration in a separate line. - Do not use C++ comments (`//`). - Spaces around operators are mandatory. - No whitespace is allowed at the end of line. - For multi-line macros, do not put whitespace before `\` character. - Precede definition of each function with a brief, non-trivial description. (Usually a single line is enough.) - Use `XXX` tag to indicate a hack, problematic code, or something to be done. - For pointer variables, place the `*` close to the variable name not pointer type. - Avoid unnecessary variable initialization. - Never type `unsigned int` - just use `unsigned` in such case. Same with `long int` and `long`, etc. - Sized types like `uint32_t`, `int64_t` should be used when there is an on-media format. Otherwise, just use `unsigned`, `long`, etc. - Functions with local scope must be declared as `static`. ### License & copyright - Make sure you have the right to submit your contribution under the BSD license, especially if it is based upon previous work. See [CONTRIBUTING.md](https://github.com/pmem/pmdk/blob/master/CONTRIBUTING.md) for details. - A copy of the [BSD-style License](https://github.com/pmem/pmdk/blob/master/LICENSE) must be placed at the beginning of each source file, script or man page (Obviously, it does not apply to README's, Visual Studio projects and \*.match files.) - When adding a new file to the repo, or when making a contribution to an existing file, feel free to put your copyright string on top of it. ### Naming convention - Keep identifier names short, but meaningful. One-letter variables are discouraged. - Use proper prefix for function name, depending on the module it belongs to. - Use *under_score* pattern for function/variable names. Please, do not use CamelCase or Hungarian notation. - UPPERCASE constant/macro/enum names. - Capitalize first letter for variables with global or module-level scope. - Avoid using `l` as a variable name, because it is hard to distinguish `l` from `1` on some displays. ### Multi-OS support (Linux/FreeBSD/Windows) - Do not add `#ifdef ` sections lightly. They should be treated as technical debt and avoided when possible. - Use `_WIN32` macro for conditional directives when including code using Windows-specific API. - Use `__FreeBSD__` macro for conditional directives for FreeBSD-specific code. - Use `_MSC_VER` macro for conditional directives when including code using VC++ or gcc specific extensions. - In case of large portions of code (i.e. a whole function) that have different implementation for each OS, consider moving them to separate files. (i.e. *xxx_linux.c*, *xxx_freebsd.c* and *xxx_windows.c*) - Keep in mind that `long int` is always 32-bit in VC++, even when building for 64-bit platforms. Remember to use `long long` types whenever it applies, as well as proper formatting strings and type suffixes (i.. `%llu`, `ULL`). - Standard compliant solutions should be used in preference of compiler-specific ones. (i.e. static inline functions versus statement expressions) - Do not use formatting strings that are not supported by Windows implementations of printf()/scanf() family. (like `%m`) - It is recommended to use `PRI*` and `SCN*` macros in printf()/scanf() functions for width-based integral types (`uint32_t`, `int64_t`, etc.). ### Debug traces and assertions - Put `LOG(3, ...)` at the beginning of each function. Consider using higher log level for most frequently called routines. - Make use of `COMPILE_ERROR_ON` and `ASSERT*` macros. - Use `ERR()` macro to log error messages. ### Unit tests - There **must** be unit tests provided for each new function/module added. - Test scripts **must** start with `#!/usr/bin/env ` for portability between Linux and FreeBSD. - Please, see [this](https://github.com/pmem/pmdk/blob/master/src/test/README) and [that](https://github.com/pmem/pmdk/blob/master/src/test/unittest/README) document to get familiar with our test framework and the guidelines on how to write and run unit tests. ### Commit messages All commit lines (entered when you run `git commit`) must follow the common conventions for git commit messages: - The first line is a short summary, no longer than **50 characters,** starting with an area name and then a colon. There should be no period after the short summary. - Valid area names are: **pmem, obj, blk, log, cto, vmem, vmmalloc, jemalloc, cpp** (for C++ bindings), **test, doc, pool** (for *libpmempool* and *pmempool*), **rpmem** (for *librpmem* and *rpmemd*), **benchmark, examples** and **common** (for everything else). - It is acceptable for the short summary to be the only thing in the commit message if it is a trivial change. Otherwise, the second line must be a blank line. - Starting at the third line, additional information is given in complete English sentences and, optionally, bulleted points. This content must not extend beyond **column 72.** - The English sentences should be written in the imperative, so you say "Fix bug X" instead of "Fixed bug X" or "Fixes bug X". - Bullet points should use hanging indents when they take up more than one line (see example below). - There can be any number of paragraphs, separated by a blank line, as many as it takes to describe the change. - Any references to GitHub issues are at the end of the commit message. For example, here is a properly-formatted commit message: ``` doc: fix code formatting in man pages This section contains paragraph style text with complete English sentences. There can be as many paragraphs as necessary. - Bullet points are typically sentence fragments - The first word of the bullet point is usually capitalized and if the point is long, it is continued with a hanging indent - The sentence fragments don't typically end with a period Ref: pmem/issues#1 ``` pmdk-1.4.1/CONTRIBUTING.md000066400000000000000000000146421331545616200147160ustar00rootroot00000000000000# Contributing to the Persistent Memory Development Kit Here you'll find instructions on how to contribute to the Persistent Memory Development Kit. Your contributions are most welcome! You'll find it is best to begin with a conversation about your changes, rather than just writing a bunch of code and contributing it out of the blue. There are several good ways to suggest new features, offer to add a feature, or just begin a dialog about the Persistent Memory Development Kit: * Open an issue in our [GitHub Issues Database](https://github.com/pmem/issues/issues) * Suggest a feature, ask a question, start a discussion, etc. in our [pmem Google group](http://groups.google.com/group/pmem) * Chat with members of the PMDK team real-time on the **#pmem** IRC channel on [OFTC](http://www.oftc.net) **NOTE: If you do decide to implement code changes and contribute them, please make sure you agree your contribution can be made available under the [BSD-style License used for the Persistent Memory Development Kit](https://github.com/pmem/pmdk/blob/master/LICENSE).** **NOTE: Submitting your changes also means that you certify the following:** ``` Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` In case of any doubt, the gatekeeper may ask you to certify the above in writing, i.e. via email or by including a `Signed-off-by:` line at the bottom of your commit comments. To improve tracking of who is the author of a contribution, we kindly ask you to use your real name (not an alias) when committing your changes to the Persistent Memory Development Kit: ``` Author: Random J Developer ``` ### Code Contributions Please feel free to use the forums mentioned above to ask for comments & questions on your code before submitting a pull request. The Persistent Memory Development Kit project uses the common *fork and merge* workflow used by most GitHub-hosted projects. The [Git Workflow blog article](http://pmem.io/2014/09/09/git-workflow.html) describes our workflow in more detail. #### Linux/FreeBSD Before contributing please remember to run: ``` $ make cstyle ``` This will check all C/C++ files in the tree for style issues. To check C++ files you have to have clang-format version 3.8+, otherwise they will be skipped. If you want to run this target automatically at build time, you can pass CSTYLEON=1 to make. If you want cstyle to be run, but not fail the build, pass CSTYLEON=2 to make. There is also a target for automatic C++ code formatting, to do this run: ``` $ make format ``` There are cases, when you might have several clang-format-X.Y binaries and either no clang-format or it pointing to an older version. In such case run: ``` $ make CLANG_FORMAT=/path/to/clang-format cstyle|format ``` #### Windows On Windows to check the code for style issues, please run: ``` $ pmdk\utils\CSTYLE.ps1 ``` To check or format C++ files, you may use a standalone Visual Studio plugin for clang-format. The plugin installer can be downloaded from [LLVM Builds](http://llvm.org/builds) page. If you are actively working on an PMDK feature, please let other developers know by [creating an issue](https://github.com/pmem/issues/issues). Use the label `Type: Feature` and assign it to yourself (due to the way GitHub permissions work, you may need to ask a team member to assign it to you). ### Bug Reports Bugs for the PMDK project are tracked in our [GitHub Issues Database](https://github.com/pmem/issues/issues). When creating a bug report issue, please provide the following information: #### PMDK version Put the release name of the version of PMDK running when the bug was discovered in a bug comment. If you saw this bug in multiple PMDK versions, please put at least the most recent version and list the others if necessary. - Stable release names are in the form `#.#` (where `#` represents an integer); for example `0.3`. - Release names from working versions look like `#.#+b#` (adding a build #) or `#.#-rc#` (adding a release candidate number) If PMDK was built from source, the version number can be retrieved from git using this command: `git describe` For binary PMDK releases, use the entire package name. For RPMs, use `rpm -q pmdk` to display the name. For Deb packages, run `dpkg-query -W pmdk` and use the second (version) string. #### Milestone field Optionally, assign the milestone the issue needs to be fixed before. #### Type: Bug label Assign the `Type: Bug` label to the issue (see [GitHub Help](https://help.github.com/articles/applying-labels-to-issues-and-pull-requests) for details). #### Priority label Optionally, assign one of the Priority labels (P1, P2, ...). The Priority attribute describes the urgency to resolve a defect and establishes the time frame for providing a verified resolution. These Priority labels are defined as: * **P1**: Showstopper bug, requiring resolution before the next release of the library. * **P2**: High-priority bug, requiring resolution although it may be decided that the bug does not prevent the next release of the library. * **P3**: Medium-priority bug. The expectation is that the bug will be evaluated and a plan will be made for when the bug will be resolved. * **P4**: Low-priority bug, the least urgent. Fixed as resources are available. Then describe the bug in the comment fields. #### Type: Feature label Assign the `Type: Feature` label to the issue, then describe the feature request in comment fields. pmdk-1.4.1/ChangeLog000066400000000000000000000455701331545616200142430ustar00rootroot00000000000000Fri Jun 29 2018 Marcin Ślusarz * Version 1.4.1 In 1.4 development cycle, we developed new daxio utility (command line tool for performing I/O on Device-DAX), but due to some complications we had to disable it just before the 1.4 release. In 1.4.1 we finally enable it. Daxio depends on ndctl v60.1. Bug fixes: - pmem: fix clflush bit position - obj: fix invalid OOMs when zones are fully packed - obj: don't register undo logs twice in memcheck - pool: fix bash completion script - pool: fix incorrect errno after transform - obj: fix clang-7 compilation - obj: test for msync failures in non-pmem path - doc: add missing field to alloc class entry point - common: (win) fix timed locks - common: provide src version in GitHub tarballs - common: fix free function in tls - common: fix double close - test: allow testing installed libraries - test: fix Valgrind vs stripped libraries issue - test: fix dependencies between tests and tools - test: fix races on make pcheck -jN - test: use libvmmalloc.so.1 - test: fix incorrect number of required dax devices - test: add suppression for leak in ld.so - test: fail if memcheck detects overlapping chunks - test: simplify time measurements in obj_sync - benchmark: check lseek() return value - examples: catch exceptions in map_cli Thu Mar 29 2018 Krzysztof Czurylo * Version 1.4 This is the first release of PMDK under a new name. The NVML project has been renamed to PMDK (Persistent Memory Development Kit). This is only the project/repo name change and it does not affect the names of the PMDK packages. See this blog article for more details on the reasons and impact of the name change: http://pmem.io/2017/12/11/NVML-is-now-PMDK.html New features: - common: support for concatenated Device-DAX devices with 2M/1G alignment - common: add support for MAP_SYNC flag - common: always enable Valgrind instrumentation (#292) - common: pool set options / headerless pools - pmem: add support for "deep flush" operation - rpmem: add rpmem_deep_persist - doc: split man pages and add per-function aliases (#385) Optimizations: - pmem: skip CPU cache flushing when eADR is available (no Windows support yet) - pmem: add AVX512F support in pmem_memcpy/memset (#656) Bug fixes: - common: fix library dependencies (#767, RHBZ #1539564) - common: use rpm-config CFLAGS/LDFLAGS when building packages (#768, RHBZ #1539564) - common: do not unload librpmem on close (#776) - common: fix NULL check in os_fopen (#813) - common: fix missing version in .pc files - obj: fix cancel of huge allocations (#726) - obj: fix error handling in pmemobj_open (#750) - obj: validate pe_offset in pmemobj_list_* APIs (#772) - obj: fix add_range with size == 0 (#781) - log: add check for negative iovcnt (#690) - rpmem: limit maximum number of lanes (#609) - rpmem: change order of memory registration (#655) - rpmem: fix removing remote pools (#721) - pool: fix error handling (#643) - pool: fix sync with switched parts (#730) - pool: fix sync with missing replica (#731) - pool: fix detection of Device DAX size (#805) - pool: fail pmempool_sync if there are no replicas (#816) - benchmark: fix calculating standard deviation (#318) - doc: clarify pmem_is_pmem behavior (#719) - doc: clarify pmemobj_root behavior (#733) Experimental features: - common: port PMDK to FreeBSD - common: add experimental suport for aarch64 - obj: introduce allocation classes - obj: introduce two-phase heap ops (reserve/publish) (#380, #415) - obj: provide basic heap statistics (#676) - obj: implement run-time pool extending (#382) - cto: add close-to-open persistence library (#192) The following features are disabled by default, until ndctl v60.0 is available: - daxio: add utility to perform I/O on Device-DAX - RAS: unsafe shutdown detection/handling Wed Dec 20 2017 Krzysztof Czurylo * Version 1.3.1 Bug fixes: - rpmem: fix issues reported by Coverity - rpmem: fix read error handling - rpmem: add fip monitor (#597) - test: add rpmemd termination handling test - cpp: fix pop.persist function in obj_cpp_ptr - rpmem: return failure for a failed allocation - rpmem: fix potential memory leak - common: fix available rm options msg (#651) - pool: fix pmempool_get_max_size - obj: fix potential deadlock during realloc (#635, #636, #637) - obj: initialize TLS data - rpmem: fix cleanup if fork() failed (#634) - obj: fix bogus OOM after exhausting first zone Thu Jul 13 2017 Krzysztof Czurylo * Version 1.3 This release introduces some useful features and optimizations in libpmemobj. Most of them are experimental and controlled by the new pmemobj_ctl APIs. For details, please check the feature requests identified by the issue numbers listed next to the items below. Other important changes are related to performance tuning and stabilization of librpmem library, which is used by libpmemobj to get remote access to persistent memory and to provide basic data replication over RDMA. The librpmem is still considered experimental. NVML for Windows is feature complete (except for libvmmalloc). This release includes the support for Unicode, long paths and the NVML installer. New features: - common: add support for concatenated DAX Devices - common: add Unicode support on Windows - common: add long path support on Windows - common: add NVML installer for Windows - pmem: make pmem_is_pmem() true for Device DAX only - obj: add pmemobj_wcsdup()/pmemobj_tx_wcsdup() APIs - obj: export non-inlined pmemobj_direct() - obj: add PMEMOBJ_NLANES env variable - cpp: introduce the allocator - cpp: add wstring version of C++ entry points - vmem: add vmem_wcsdup() API entry - pool: add pmempool_rm() function (#307) - pool: add --force flag for create command (#529) - benchmark: add a minimal execution time option - benchmark: add thread affinity option - benchmark: print 99% and 99.9% percentiles - doc: separate Linux/Windows version of web-based man pages Optimizations: - obj: cache _pobj_cached_pool in pmemobj_direct() - obj: optimize thread utilization of buckets - obj: stop grabbing a lock when querying pool ptr - rpmem: use multiple endpoints Bug fixes: - common: fix issues reported by static code analyzers - pmem: fix mmap() implementation on Windows - pmem: fix mapping addr/length alignment on Windows - pmem: fix PMEM_MMAP_HINT implementation on Windows - pmem: fix pmem_is_pmem() on invalid memory ranges - pmem: fix wrong is_pmem returned by pmem_map_file() - pmem: fix mprotect() for private mappings on Windows - pmem: modify pmem_is_pmem() behavior for len==0 - obj: add failsafe to prevent allocs in constructor - cpp: fix swap implementation - cpp: fix sync primitives' constructors - cpp: fix wrong pointer type in the allocator - cpp: return persistent_ptr::swap to being public - pool: treat invalid answer as 'n' - pool: unify flags value for dry run - pool: transform for remote replicas - rpmem: persistency method detection - benchmark: fix time measurement Experimental features/optimizations: - obj: pmemobjctl - statistics and control submodule (#194, #211) - obj: zero-overhead allocations - customizable alloc header (#347) - obj: flexible run size index (#377) - obj: dynamic range cache (#378) - obj: asynchronous post-commit (#381) - obj: configurable object cache (#515) - obj: add cache size and threshold tx params - obj: add CTL var for suppressing expensive checks - rpmem: add rpmem_set_attr() API entry - rpmem: switch to libfabric v1.4.2 Thu May 18 2017 Krzysztof Czurylo * Version 1.2.3 Bug fixes: - test: extend timeout for selected tests - test: reduce number of operations in obj_tx_mt - test: define cfree() as free() in vmmalloc_calloc Other changes: - common: move Docker images to new repo Sat Apr 15 2017 Krzysztof Czurylo * Version 1.2.2 Bug fixes: - pmempool: fix mapping type in pool_params_parse - test: limit number of arenas in vmem_stats - test: do not run pool_lock test as root - common: fix pkg-config files - common: fix building packages for Debian Tue Feb 21 2017 Krzysztof Czurylo * Version 1.2.1 This NVML release changes the behavior of pmem_is_pmem() on Linux. The pmem_is_pmem() function will now return true only if the entire range is mapped directly from Device DAX (/dev/daxX.Y) without an intervening file system, and only if the corresponding file mapping was created with pmem_map_file(). See libpmem(3) for details. Bug fixes: - jemalloc: fix test compilation on Fedora 26 (rawhide) - test: fix cpp test compilation on Fedora 26 (rawhide) - common: use same queue.h on linux and windows - common: queue.h clang static analyzer fix - common: fix path handling in build-dpkg.sh - test: fix match files in pmempool_transform/TEST8 Fri Dec 30 2016 Krzysztof Czurylo * Version 1.2 - Windows Technical Preview #1 This is the first Technical Preview release of NVML for Windows. It is based on NVML 1.2 version, but not all the 1.2 features are ported to Windows. In particular, Device DAX and remote access to persistent memory (librpmem) are not supported by design. NOTE: This release has not gone through the full validation cycle, but only through some basic tests on Travis and AppVeyor. Thus, it cannot be assumed "Production quality" and should not be used in production environments. Besides several minor improvements and bug fixes, all the other changes since NVML 1.2 release were related to Windows support: - win: port libvmem (and jemalloc) - win: benchmarks Windows port - win: fix mapping files of unaligned length - win: clean up possible race condition in mmap_init() - win: enable QueryVirtualMemoryInformation() in pmem_is_pmem() - test: check open handles at START/DONE - test: port all the remaining unit tests (scope, pmem_map, obj_debug, util_poolset, pmempool_*) - win: add resource files for versioning Known issues and limitations of Windows version of NVML: - Unicode support is missing. The UTF/USC-encoded file paths or pool set files may not be handled correctly. - The libvmmalloc library is not ported yet. - The on-media format of pmem pools is not portable at the moment. The pmem pools created using Windows version of NVM libraries cannot be open on Linux and vice versa. - Despite the fact the current version of NVML would work with any recent version of Windows OS, to take full advantage of PMEM and NVML features and to benefit from the PMEM performance, the recommended platforms needs be equipped with the real NVDIMMs hardware and should support the native, Microsoft's implementation of DAX-enabled file system (i.e. Windows Server 2016 or later). In case of using NVML with older versions of Windows or with the custom implementation of PMEM/DAX drivers, the performance might not be satisfactory. Please, contact the provider of PMEM/DAX drivers for your platform to get the customized version of NVML in such case. Thu Dec 15 2016 Krzysztof Czurylo * Version 1.2 This NVML release causes a "flag day" for libpmemobj. The pmemobj pools built under NVML 1.1 are incompatible with pools built under NVML 1.2 and later. This is because an issue was discovered with the alignment of locks (#358) and, although rare, the issue potentially impacts program correctness, making the fix mandatory. The major version number of the pmemobj pool layout and the version of the libpmemobj API is changed to prevent the use of the potentially incorrect layout. Other key changes introduced in this release: - Add Device DAX support, providing that "optimized flush" mechanism defined in SNIA NVM Programming Model can safely be used, even if PMEM-aware file system supporting that model is not available, or if the user does not want to use the file system for some reason. - Add a package for libpmemobj C++ bindings. C++ API is no longer considered experimental. Web-based documentation for C++ API is available on http://pmem.io. - Add "sync" and "transform" commands to pmempool utility. The "sync" command allows to recover missing or corrupted part(s) of a pool set from a healthy replica, while the "transform" command is a convenient way for modifying the structure of an existing pool set, i.e. by adding or removing replicas. - Add experimental support for remote access to persistent memory and basic remote data replication over RDMA (librpmem). Experimental support for remote replicas is also provided by libpmemobj library. New features: - common: add Device DAX support (#197) - obj: add C++ bindings package (libpmemobj++-devel) - obj: add TOID_OFFSETOF macro - pmempool: add "sync" and "transform" commands (#172, #196) Bug fixes: - obj: force alignment of pmem lock structures (#358) - blk: cast translation entry to uint64_t when calculating data offset - obj: fix Valgrind instrumentation of chunk headers and cancelled allocations - obj: set error message when user called pmemobj_tx_abort() - obj: fix status returned by pmemobj_list_insert() (#226) - obj: defer allocation of global structures Optimizations: - obj: fast path for pmemobj_pool_by_ptr() when inside a transaction - obj: simplify and optimize allocation class generation Experimental features: - rpmem: add support for remote access to persistent memory and basic remote data replication over RDMA - libpmempool: add pmempool_sync() and pmempool_transform() (#196) - obj: introduce pmemobj_oid() - obj: add pmemobj_tx_xalloc()/pmemobj_tx_xadd_range() APIs and the corresponding macros - obj: add transaction stage transition callbacks Thu Jun 23 2016 Krzysztof Czurylo * Version 1.1 This NVML release introduces a new version of libpmemobj pool layout. Internal undo log structure has been modified to improve performance of pmemobj transactions. Memory pools created with older versions of the libpmemobj library must be converted to the new format using "pmempool convert" command. See pmempool-convert(1) for details. A new "libpmempool" library is available, providing support for off-line pool management and diagnostics. Initially it provides only "check" and "repair" operations for log and blk memory pools, and for BTT devices. Other changes: - pmem: deprecate PCOMMIT - blk: match BTT Flog initialization with Linux NVDIMM BTT - pmem: defer pmem_is_pmem() initialization (#158) - obj: add TOID_TYPEOF macro Bug fixes: - doc: update description of valid file size units (#133) - pmempool: fix --version short option in man page (#135) - pmempool: print usage when running rm without arg (#136) - cpp: clarify polymorphism in persistent_ptr (#150) - obj: let the before flag be any non-zero value (#151) - obj: fix compare array pptr to nullptr (#152) - obj: cpp pool.get_root() fix (#156) - log/blk: set errno if replica section is specified (#161) - cpp: change exception message (#163) - doc: remove duplicated words in man page (#164) - common: always append EXTRA_CFLAGS after our CFLAGS Experimental features: - Implementation of C++ bindings for libpmempobj is complete. Web-based documentation for C++ API is available on http://pmem.io. Note that C++ API is still considered experimental. Do not use it in production environments. - Porting NVML to Windows is in progress. There are MS Visual Studio solution/projects available, allowing to compile libpmem, libpmemlog, libpmemblk and libpmemobj on Windows, but the libraries are not fully functional and most of the test are not enabled yet. Thu Apr 07 2016 Krzysztof Czurylo * Version 1.0 The API of six libraries (libpmem, libpmemblk, libpmemlog, libpmemobj, libvmem, libvmmalloc) is complete and stable. The on-media layout of persistent memory pools will be maintained from this point, and if changed it will be backward compatible. Man pages are all complete. This release has been validated to "Production quality". For the purpose of new features planned for next releases of NVML there have been some API modifications made: - pmem: pmem_map replaced with pmem_map_file - log/blk: 'off_t' substituted with 'long long' - obj: type numbers extended to 64-bit - obj: new entry points and macros added: pmemobj_tx_errno, pmemobj_tx_lock, pmemobj_mutex_timedlock, TX_ADD_DIRECT, TX_ADD_FIELD_DIRECT, TX_SET_DIRECT Other key changes since version 0.4 include: - common: updated/fixed installation scripts - common: eliminated dependency on libuuid - pmem: CPU features/ISA detection using CPUID - obj: improved error handling - obj: atomic allocation fails if constructor returns error - obj: multiple performance optimizations - obj: object store refactoring - obj: additional examples and benchmarks This release also introduces a prototype implementation of C++ bindings for libpmemobj. Note that C++ API is still experimental and should not be used in production environments. Fri Dec 04 2015 Krzysztof Czurylo * Version 0.4 This NVML version primarily focuses on improving code quality and reliability. In addition to a couple of bug fixes, the changes include: - benchmarks for libpmemobj, libpmemblk and libvmem - additional pmemobj tests and examples - pool mapping address randomization - added pmempool "rm" command - eliminated libpmem dependency on libpthread - enabled extra warnings - minor performance improvements Man pages are all complete. This release is considered "Beta quality" by the team, having been thoroughly validated, including significant performance analysis. The pmempool command does not yet support "check" and "repair" operations for pmemobj type pools. Sun Sep 13 2015 Andy Rudoff * Version 0.3 NVML is now feature complete, adding support for: - pool sets - pmemobj local replication (active/passive) - experimental valgrind support - pmempool support for all pool types Man pages are all complete. This release is considered "Alpha quality" by the team, having gone through significant validation but only some performance analysis at this point. Tue Jun 30 2015 Andy Rudoff * Version 0.2 NVML now consists of six libraries: - libpmem (basic flushing, etc) - libpmemblk, libpmemlog, libpmemobj (transactions) - libvmem, libvmmalloc (volatile use of pmem) The "pmempool" command is available for managing pmem files. Man pages for all the above are complete. The only things documented in man pages but not implemented are: - pmem sets (ability to spread a pool over a set of files) - replication (coming for libpmemobj) The pmempool command does not yet support pmemobj type pools. Thu Sep 11 2014 Andy Rudoff * Version 0.1 Initial development done in 0.1 builds pmdk-1.4.1/GIT_VERSION000066400000000000000000000000441331545616200142270ustar00rootroot000000000000009a4265a1c6 (tag: 1.4.1, stable-1.4)pmdk-1.4.1/LICENSE000066400000000000000000000036721331545616200134730ustar00rootroot00000000000000Copyright 2014-2018, Intel Corporation Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Everything in this source tree is covered by the previous license with the following exceptions: * src/jemalloc has its own (somewhat similar) license contained in src/jemalloc/COPYING. * src/common/valgrind/valgrind.h, src/common/valgrind/memcheck.h, src/common/valgrind/helgrind.h, src/common/valgrind/drd.h are covered by another similar BSD license variant, contained in those files. * utils/cstyle (used only during development) licensed under CDDL. pmdk-1.4.1/Makefile000066400000000000000000000112071331545616200141170ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Makefile -- top-level Makefile for PMDK # # Use "make" to build the library. # # Use "make doc" to build documentation. # # Use "make test" to build unit tests. Add "SKIP_SYNC_REMOTES=y" to skip # or "FORCE_SYNC_REMOTES=y" to force syncing remote nodes if any is defined. # # Use "make check" to run unit tests. # # Use "make check-remote" to run only remote unit tests. # # Use "make clean" to delete all intermediate files (*.o, etc). # # Use "make clobber" to delete everything re-buildable (binaries, etc.). # # Use "make cstyle" to run cstyle on all C source files # # Use "make check-license" to check copyright and license in all source files # # Use "make rpm" to build rpm packages # # Use "make dpkg" to build dpkg packages # # Use "make source DESTDIR=path_to_dir" to copy source files # from HEAD to 'path_to_dir/pmdk' directory. # # As root, use "make install" to install the library in the usual # locations (/usr/local/lib, /usr/local/include, and /usr/local/share/man). # You can provide custom directory prefix for installation using # DESTDIR variable e.g.: "make install DESTDIR=/opt" # You can override the prefix within DESTDIR using prefix variable # e.g.: "make install prefix=/usr" include src/common.inc include src/version.inc RPM_BUILDDIR=rpmbuild DPKG_BUILDDIR=dpkgbuild EXPERIMENTAL ?= n BUILD_PACKAGE_CHECK ?= y BUILD_RPMEM ?= y TEST_CONFIG_FILE ?= $(CURDIR)/src/test/testconfig.sh rpm : override DESTDIR=$(CURDIR)/$(RPM_BUILDDIR) dpkg: override DESTDIR=$(CURDIR)/$(DPKG_BUILDDIR) rpm dpkg: override prefix=/usr all: $(MAKE) -C src $@ doc: $(MAKE) -C doc all clean: $(MAKE) -C src $@ $(MAKE) -C doc $@ $(MAKE) -C utils $@ $(RM) -r $(RPM_BUILDDIR) $(DPKG_BUILDDIR) $(RM) -f $(GIT_VERSION) clobber: $(MAKE) -C src $@ $(MAKE) -C doc $@ $(MAKE) -C utils $@ $(RM) -r $(RPM_BUILDDIR) $(DPKG_BUILDDIR) rpm dpkg $(RM) -f $(GIT_VERSION) test check pcheck check-remote: all $(MAKE) -C src $@ cstyle: @utils/check-commit.sh $(MAKE) -C src $@ $(MAKE) -C utils $@ @echo Checking files for whitespace issues... @utils/check_whitespace -g @echo Done. format: $(MAKE) -C src $@ $(MAKE) -C utils $@ @echo Done. check-license: $(MAKE) -C utils $@ @utils/check_license/check-headers.sh \ $(TOP) \ utils/check_license/check-license \ LICENSE @echo Done. sparse: $(MAKE) -C src sparse source: $(if $(shell git rev-parse 2>&1), $(error Not a git repository)) $(if $(DESTDIR), , $(error Please provide DESTDIR variable)) $(if $(shell git status --porcelain), $(error Working directory is dirty: $(shell git status --porcelain))) mkdir -p $(DESTDIR)/pmdk echo -n $(SRCVERSION) > $(DESTDIR)/pmdk/.version git archive HEAD | tar -x -C $(DESTDIR)/pmdk pkg-clean: $(RM) -r $(DESTDIR) rpm dpkg: pkg-clean source +utils/build-$@.sh -t $(SRCVERSION) -s $(DESTDIR)/pmdk -w $(DESTDIR) -o $(CURDIR)/$@\ -e $(EXPERIMENTAL) -c $(BUILD_PACKAGE_CHECK) -r $(BUILD_RPMEM)\ -f $(TEST_CONFIG_FILE) -n $(NDCTL_ENABLE) install uninstall: $(MAKE) -C src $@ $(MAKE) -C doc $@ .PHONY: all clean clobber test check cstyle check-license install uninstall\ source rpm dpkg pkg-clean pcheck check-remote format doc $(SUBDIRS) pmdk-1.4.1/README.md000066400000000000000000000312601331545616200137370ustar00rootroot00000000000000pmdk: Persistent Memory Development Kit ======================================= [![Build Status](https://travis-ci.org/pmem/pmdk.svg?branch=master)](https://travis-ci.org/pmem/pmdk) [![Build status](https://ci.appveyor.com/api/projects/status/u2l1db7ucl5ktq10/branch/master?svg=true&pr=false)](https://ci.appveyor.com/project/pmem/pmdk/branch/master) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/3015.svg)](https://scan.coverity.com/projects/pmem-pmdk) [![PMDK release version](https://img.shields.io/github/release/pmem/pmdk.svg)](https://github.com/pmem/pmdk/releases/latest) [![Coverage Status](https://codecov.io/github/pmem/pmdk/coverage.svg?branch=master)](https://codecov.io/gh/pmem/pmdk/branch/master) This is the top-level README.md of the Persistent Memory Development Kit. For more information, see http://pmem.io. ### The Libraries ### Please see the file [LICENSE](https://github.com/pmem/pmdk/blob/master/LICENSE) for information on how this library is licensed. This tree contains a collection of libraries for using Non-Volatile Memory (NVM). There are currently nine libraries: * **libpmem** -- basic pmem operations like flushing * **libpmemblk**, **libpmemlog**, **libpmemobj** -- pmem transactions * **libvmem**, **libvmmalloc**1 -- volatile use of pmem * **libpmempool** -- persistent memory pool management * **librpmem**1 -- remote access to persistent memory (EXPERIMENTAL) * **libpmemcto** -- close-to-open persistence (EXPERIMENTAL) and two command-line utilities: * **pmempool** -- standalone tool for off-line pool management * **daxio** -- perform I/O on Device-DAX devices or zero a Device-DAX device These libraries and utilities are described in more detail on the [pmem web site](http://pmem.io). There you'll find man pages, examples, and tutorials. **Currently, these libraries only work on 64-bit Linux, Windows**2 **and 64-bit FreeBSD 11+**3. >1 Not supported on Windows. > >2 PMDK for Windows is feature complete, but not yet considered production quality. > >3 DAX and **libfabric** are not yet supported in FreeBSD, so at this time PMDK is available as a technical preview release for development purposes. ### Pre-Built Packages ### If you want to install these libraries to try them out of your system, you can either install pre-built packages, which we build for every stable release, or clone the tree and build it yourself. Builds are tagged something like `0.2+b1`, which means *Build 1 on top of version 0.2* and `0.2-rc3`, which means *Release Candidate 3 for version 0.2*. **Stable** releases are the simpler *major.minor* tags like `0.2`. To find pre-build packages, check the Downloads associated with the stable releases on the [github release page](https://github.com/pmem/pmdk/releases). ### Building The Source ### The source tree is organized as follows: * **doc** -- man pages describing each library contained here * **src** -- the source for the libraries * **src/include** -- public header files for all the libraries * **src/benchmarks** -- benchmarks used by development team * **src/examples** -- brief example programs using these libraries * **src/freebsd** -- FreeBSD-specific header files * **src/test** -- unit tests used by development team * **src/tools** -- various tools developed for PMDK * **src/windows** -- Windows-specific source and header files * **utils** -- utilities used during build & test * **CONTRIBUTING.md** -- instructions for people wishing to contribute * **CODING_STYLE.md** -- coding standard and conventions for PMDK To build this library on Linux, you may need to install the following required packages on the build system: * **autoconf** * **pkg-config** The following packages are required only by selected PMDK components or features. If not present, those components or features may not be available: * **libfabric** (v1.4.2 or later) -- required by **librpmem** * **ndctl** and **daxctl** (v60.1 or later) -- required by **daxio** On Windows, to build PMDK and run the tests you need: * **MS Visual Studio 2015** * [Windows SDK 10.0.14393](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) (or later) * **perl** (i.e. [ActivePerl](http://www.activestate.com/activeperl/downloads)) * **PowerShell 5** To build and test this library on FreeBSD, you may need to install the following required packages on the build system: * **autoconf** * **bash** * **binutils** * **coreutils** * **e2fsprogs-libuuid** * **gmake** * **libunwind** * **ncurses**4 * **pkgconf** Some tests and example applications require additional packages, but they do not interrupt building if they are missing. An appropriate message is displayed instead. For details please read the **DEPENDENCIES** section in the appropriate README file. See our [Dockerfiles](https://github.com/pmem/pmdk/blob/master/utils/docker/images/) to get an idea what packages are required to build the entire PMDK, with all the tests and examples on the _Travis-CI_ system. >4 The pkg version of ncurses is required for proper operation; the base version included in FreeBSD is not sufficient. #### Building PMDK on Linux or FreeBSD #### To build the latest development version, just clone this tree and build the master branch: ``` $ git clone https://github.com/pmem/pmdk $ cd pmdk ``` Once the build system is setup, the Persistent Memory Development Kit is built using the `make`5 command at the top level: ``` $ make ``` If you want to compile, and hopefully run the builtin tests, with a different compiler, you have to provide the `CC` and `CXX` variables. For example: ``` $ make CC=clang CXX=clang++ ``` These variables are independent and setting `CC=clang` does not set `CXX=clang++`. Once the make completes,6 all the libraries are built and the examples under `src/examples` are built as well. You can play with the library within the build tree, or install it locally on your machine. Installing the library is more convenient since it installs man pages and libraries in the standard system locations: ``` (as root...) # make install ``` To install this library into other locations, you can use the prefix variable, e.g.: ``` $ make install prefix=/usr/local ``` This will install files to /usr/local/lib, /usr/local/include /usr/local/share/man. To prepare this library for packaging, you can use the DESTDIR variable, e.g.: ``` $ make install DESTDIR=/tmp ``` This will install files to /tmp/usr/lib, /tmp/usr/include /tmp/usr/share/man. The man pages (groff files) are generated as part of the `install` rule. To generate the documentation separately, run: ``` $ make doc ``` **DEPENDENCIES:** doxygen, graphviz, pandoc7 To install a complete copy of the source tree to $(DESTDIR)/pmdk: ``` $ make source DESTDIR=some_path ``` To build rpm packages on rpm-based distributions: ``` $ make rpm ``` If you want to build packages without running tests, run: ``` $ make BUILD_PACKAGE_CHECK=n rpm ``` **DEPENDENCIES:** rpmbuild To build dpkg packages on Debian-based distributions: ``` $ make dpkg ``` If you want to build packages without running tests, run: ``` $ make BUILD_PACKAGE_CHECK=n dpkg ``` **DEPENDENCIES:** devscripts If you want to invoke make with the same variables multiple times, you can create user.mk file in the top level directory and put all variables there. For example: ``` $ cat user.mk EXTRA_CFLAGS_RELEASE = -ggdb -fno-omit-frame-pointer PATH += :$HOME/valgrind/bin ``` This feature is intended to be used only by developers and it may not work for all variables. Please do not file bug reports about it. Just fix it and make a PR. >5 For FreeBSD, use `gmake` rather than `make`. > >6 By default all code is built with the -Werror flag, which fails the whole build when the compiler emits any warning. This is very useful during development, but can be annoying in deployment. If you want to disable -Werror, use the EXTRA_CFLAGS variable: ``` $ make EXTRA_CFLAGS="-Wno-error" ``` >or ``` $ make EXTRA_CFLAGS="-Wno-error=$(type-of-warning)" ``` > >7Pandoc is provided by the **hs-pandoc** package on FreeBSD. #### Testing the Libraries #### Before running the tests, you may need to prepare a test configuration file (src/test/testconfig.sh). Please see the available configuration settings in the example file (src/test/testconfig.sh.example). To build and run the unit tests: ``` $ make check ``` To run a specific subset of tests, run for example: ``` $ make check TEST_TYPE=short TEST_BUILD=debug TEST_FS=pmem ``` To modify the timeout which is available for **check** type tests, run: ``` $ make check TEST_TIME=1m ``` This will set the timeout to 1 minute. Please refer to the **src/test/README** for more details on how to run different types of tests. The libraries support standard Valgrind drd, helgrind and memcheck, as well as a PM-aware version of [Valgrind](https://github.com/pmem/valgrind)8. By default support for all tools is enabled. If you wish to disable it, supply the compiler with **VG_\_ENABLED** flag set to 0, for example: ``` $ make EXTRA_CFLAGS=-DVG_MEMCHECK_ENABLED=0 ``` **VALGRIND_ENABLED** flag, when set to 0, disables all Valgrind tools (drd, helgrind, memcheck and pmemcheck).8 The **SANITIZE** flag allows the libraries to be tested with various sanitizers. For example, to test the libraries with AddressSanitizer and UndefinedBehaviorSanitizer, run: ``` $ make SANITIZE=address,undefined clobber check ``` If you wish to run C++ standard library containers tests, you need to set the path to your custom versions of either gcc or libc++. For gcc run: ``` $ make USE_CUSTOM_GCC=1 GCC_INCDIR=/path/to/includes GCC_LIBDIR=/path/to/lib check ``` If you want to use a custom version of libc++ run: ``` $ make USE_LLVM_LIBCPP=1 LIBCPP_INCDIR=/path/to/includes/ LIBCPP_LIBDIR=/path/to/lib check ``` Please remember to set the appropriate versions of *CC/CXX* when using custom versions of the library. For example, when using a custom version of libc++(version 3.9) installed to /usr/local/libcxx, to execute the tests run: ``` $ CC=clang CXX=clang++ make USE_LLVM_LIBCPP=1 LIBCPP_INCDIR=/usr/local/libcxx/include/c++/v1 LIBCPP_LIBDIR=/usr/local/libcxx/lib check ``` >8 PM-aware Valgrind is not yet available for FreeBSD. > >9 The address sanitizer is not supported for libvmmalloc on FreeBSD and will be ignored. #### Building PMDK on Windows #### Clone the PMDK tree and open the solution: ``` > git clone https://github.com/pmem/pmdk > cd pmdk/src > devenv PMDK.sln ``` Select the desired configuration (Debug or Release) and build the solution (i.e. by pressing Ctrl-Shift-B). #### Testing the Libraries #### Before running the tests, you may need to prepare a test configuration file (src/test/testconfig.ps1). Please see the available configuration settings in the example file (src/test/testconfig.ps1.example). To run the unit tests, open the PowerShell console and type: ``` > cd pmdk/src/test > RUNTESTS.ps1 ``` To run a specific subset of tests, run for example: ``` > RUNTESTS.ps1 -b debug -t short ``` To run just one test, run for example: ``` > RUNTESTS.ps1 -b debug -i pmem_is_pmem ``` To modify the timeout, run: ``` > RUNTESTS.ps1 -o 3m ``` This will set the timeout to 3 minutes. To display all the possible options, run: ``` > RUNTESTS.ps1 -h ``` Please refer to the **src/test/README** for more details on how to run different types of tests. ### The librpmem and rpmemd packages ### **NOTE:** The **libfabric** package required to build the **librpmem** and **rpmemd** is not yet available on stable Debian-based distributions. This makes it impossible to create Debian packages. If you want to build Debian packages of **librpmem** and **rpmemd** run: ``` $ make RPMEM_DPKG=y dpkg ``` ### Experimental Packages ### Some components in the source tree are treated as experimental. By default those components are built but not installed (and thus not included in packages). If you want to build/install experimental packages run: ``` $ make EXPERIMENTAL=y [install,rpm,dpkg] ``` ### Experimental support for 64-bit ARM ### There is an initial support for 64-bit ARM processors provided, currently only for aarch64. All the PMDK libraries except **librpmem** can be built for 64-bit ARM. The examples, tools and benchmarks are not ported yet and may not get built on ARM cores. **NOTE:** The support for ARM processors is highly experimental. The libraries are only validated to "early access" quality with Cortex-A53 processor. ### Contacts ### For more information on this library, contact Marcin Slusarz (marcin.slusarz@intel.com), Andy Rudoff (andy.rudoff@intel.com), or post to our [Google group](http://groups.google.com/group/pmem). pmdk-1.4.1/appveyor.yml000066400000000000000000000043641331545616200150550ustar00rootroot00000000000000version: 1.3.{build} os: Visual Studio 2015 platform: x64 install: - ps: Install-PackageProvider -Name NuGet -Force - ps: Install-Module PsScriptAnalyzer -Force configuration: - Debug - Release - Setup environment: solutionname: PMDK.sln matrix: fast_finish: true before_build: - ps: >- if ($Env:CONFIGURATION -eq "Debug") { utils/CSTYLE.ps1 if ($LASTEXITCODE -ne 0) { exit 1 } utils/CHECK_WHITESPACE.ps1 if ($LASTEXITCODE -ne 0) { exit 1 } utils/ps_analyze.ps1 if ($LASTEXITCODE -ne 0) { exit 1 } perl utils/sort_solution check if ($LASTEXITCODE -ne 0) { exit 1 } } build_script: - ps: >- if ($Env:CONFIGURATION -ne "Setup") { msbuild src\$Env:solutionname /property:Configuration=$Env:CONFIGURATION /m /v:m } else { msbuild src\$Env:solutionname /property:Configuration=Debug /m /v:m msbuild src\$Env:solutionname /property:Configuration=Release /m /v:m $Env:DEVENV="$Env:VS140COMNTOOLS\..\IDE\devenv.com" &$Env:DEVENV src\$Env:solutionname /build Release /project src\windows\setup\setup.vdproj } after_build: - ps: >- if ($Env:CONFIGURATION -eq "Setup") { PowerShell -File "src\windows\setup\OUTPUT_MSI.PS1" ` -projectdir ((Get-Location).Path+"\src\windows\setup")` -configuration $Env:CONFIGURATION } else { utils/CREATE-ZIP.ps1 -b $Env:CONFIGURATION } test_script: - ps: >- if ($Env:CONFIGURATION -ne "Setup") { cd src/test md C:\temp echo "`$Env:NON_PMEM_FS_DIR = `"C:\temp`"" >> testconfig.ps1 echo "`$Env:PMEM_FS_DIR = `"C:\temp`"" >> testconfig.ps1 echo "`$Env:PMEM_FS_DIR_FORCE_PMEM = `"1`"" >> testconfig.ps1 echo "`$Env:UNITTEST_NO_ABORT_MSG = `"1`"" >> testconfig.ps1 echo "`$Env:TM = `"1`"" >> testconfig.ps1 } if ($Env:CONFIGURATION -eq "Debug") { ./RUNTESTS.ps1 -b debug -o 4m } if ($Env:CONFIGURATION -eq "Release") { ./RUNTESTS.ps1 -b nondebug -o 4m } artifacts: - path: 'src\windows\setup\*.msi' name: PMDK_msi - path: 'src\x64\*.zip' name: PMDK - path: '*examples*.zip' name: PMDK_examples pmdk-1.4.1/doc/000077500000000000000000000000001331545616200132235ustar00rootroot00000000000000pmdk-1.4.1/doc/.gitignore000066400000000000000000000000731331545616200152130ustar00rootroot00000000000000*.txt *.html *.gz cpp_html LICENSE web_linux/ web_windows/ pmdk-1.4.1/doc/Makefile000066400000000000000000000341061331545616200146670ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # doc/Makefile -- Makefile for PMDK man pages # include ../src/common.inc MANPAGES_7_MD = libpmem/libpmem.7.md libpmemblk/libpmemblk.7.md libpmemlog/libpmemlog.7.md \ libpmemobj/libpmemobj.7.md libpmempool/libpmempool.7.md libvmem/libvmem.7.md \ libvmmalloc/libvmmalloc.7.md libpmemcto/libpmemcto.7.md MANPAGES_5_MD = poolset/poolset.5.md MANPAGES_3_MD = libpmem/pmem_flush.3.md libpmem/pmem_is_pmem.3.md libpmem/pmem_memmove_persist.3.md \ libpmemblk/pmemblk_bsize.3.md libpmemblk/pmemblk_create.3.md libpmemblk/pmemblk_read.3.md libpmemblk/pmemblk_set_zero.3.md \ libpmemlog/pmemlog_append.3.md libpmemlog/pmemlog_create.3.md libpmemlog/pmemlog_nbyte.3.md libpmemlog/pmemlog_tell.3.md \ libpmemobj/oid_is_null.3.md libpmemobj/pmemobj_action.3.md libpmemobj/pmemobj_alloc.3.md libpmemobj/pmemobj_ctl_get.3.md libpmemobj/pmemobj_first.3.md \ libpmemobj/pmemobj_list_insert.3.md libpmemobj/pmemobj_memcpy_persist.3.md libpmemobj/pmemobj_mutex_zero.3.md \ libpmemobj/pmemobj_open.3.md libpmemobj/pmemobj_root.3.md libpmemobj/pmemobj_tx_begin.3.md libpmemobj/pmemobj_tx_add_range.3.md \ libpmemobj/pmemobj_tx_alloc.3.md libpmemobj/pobj_layout_begin.3.md libpmemobj/pobj_list_head.3.md libpmemobj/toid_declare.3.md \ libpmempool/pmempool_check_init.3.md libpmempool/pmempool_rm.3.md libpmempool/pmempool_sync.3.md \ libvmem/vmem_create.3.md libvmem/vmem_malloc.3.md \ libpmemcto/pmemcto_open.3.md \ libpmemcto/pmemcto_malloc.3.md libpmemcto/pmemcto_aligned_alloc.3.md \ libpmemcto/pmemcto_strdup.3.md libpmemcto/pmemcto_wcsdup.3.md \ libpmemcto/pmemcto_set_root_pointer.3.md \ libpmemcto/pmemcto_malloc_usable_size.3.md \ libpmemcto/pmemcto_stats_print.3.md MANPAGES_1_MD = pmempool/pmempool.1.md pmempool/pmempool-info.1.md pmempool/pmempool-create.1.md \ pmempool/pmempool-check.1.md pmempool/pmempool-dump.1.md pmempool/pmempool-rm.1.md \ pmempool/pmempool-convert.1.md pmempool/pmempool-sync.1.md pmempool/pmempool-transform.1.md MANPAGES_3_DUMMY = pmem_drain.3 pmem_has_hw_drain.3 pmem_has_auto_flush.3 \ pmem_persist.3 pmem_msync.3 pmem_map_file.3 pmem_deep_persist.3 pmem_deep_flush.3 pmem_deep_drain.3 pmem_unmap.3 \ pmem_memcpy_persist.3 pmem_memset_persist.3 pmem_memmove_nodrain.3 pmem_memcpy_nodrain.3 pmem_memset_nodrain.3 \ pmem_check_version.3 pmem_errormsg.3 \ pmemblk_nblock.3 \ pmemblk_open.3 pmemblk_close.3 \ pmemblk_write.3 \ pmemblk_set_error.3 \ pmemblk_check_version.3 pmemblk_check.3 pmemblk_errormsg.3 pmemblk_set_funcs.3 \ pmemlog_rewind.3 pmemlog_walk.3 \ pmemlog_open.3 pmemlog_close.3 \ pmemlog_appendv.3 \ pmemlog_check_version.3 pmemlog_check.3 pmemlog_errormsg.3 pmemlog_set_funcs.3 \ pmempool_check.3 pmempool_check_end.3 \ pmempool_transform.3 \ pmempool_check_version.3 pmempool_errormsg.3 \ vmem_create_in_region.3 vmem_delete.3 vmem_check.3 vmem_stats_print.3 \ vmem_calloc.3 vmem_realloc.3 vmem_free.3 vmem_aligned_alloc.3 vmem_strdup.3 vmem_wcsdup.3 vmem_malloc_usable_size.3 \ vmem_check_version.3 vmem_errormsg.3 vmem_set_funcs.3 \ oid_equals.3 pmemobj_direct.3 pmemobj_oid.3 pmemobj_type_num.3 pmemobj_pool_by_oid.3 pmemobj_pool_by_ptr.3 \ pmemobj_zalloc.3 pmemobj_xalloc.3 pmemobj_free.3 pmemobj_realloc.3 pmemobj_zrealloc.3 pmemobj_strdup.3 pmemobj_wcsdup.3 pmemobj_alloc_usable_size.3 \ pobj_new.3 pobj_alloc.3 pobj_znew.3 pobj_zalloc.3 pobj_realloc.3 pobj_zrealloc.3 pobj_free.3 \ pobj_layout_toid.3 pobj_layout_root.3 pobj_layout_name.3 pobj_layout_end.3 pobj_layout_types_num.3 \ pmemobj_ctl_set.3 pmemobj_ctl_exec.3\ pmemobj_create.3 pmemobj_close.3 \ pmemobj_list_insert_new.3 pmemobj_list_remove.3 pmemobj_list_move.3 \ toid_declare_root.3 toid.3 toid_type_num.3 toid_type_num_of.3 toid_valid.3 oid_instanceof.3 toid_assign.3 toid_is_null.3 toid_equals.3 toid_typeof.3 toid_offsetof.3 direct_rw.3 d_rw.3 direct_ro.3 d_ro.3 \ pmemobj_memset_persist.3 pmemobj_persist.3 pmemobj_flush.3 pmemobj_drain.3 \ pmemobj_tx_stage.3 pmemobj_tx_lock.3 pmemobj_tx_abort.3 pmemobj_tx_commit.3 pmemobj_tx_end.3 pmemobj_tx_errno.3 \ pmemobj_tx_process.3 pmemobj_tx_add_range_direct.3 pmemobj_tx_xadd_range.3 pmemobj_tx_xadd_range_direct.3 \ pmemobj_tx_zalloc.3 pmemobj_tx_xalloc.3 pmemobj_tx_realloc.3 pmemobj_tx_zrealloc.3 pmemobj_tx_strdup.3 pmemobj_tx_wcsdup.3 pmemobj_tx_free.3 \ tx_begin_param.3 tx_begin_cb.3 tx_begin.3 tx_onabort.3 tx_oncommit.3 tx_finally.3 tx_end.3 \ tx_add.3 tx_add_field.3 tx_add_direct.3 tx_add_field_direct.3 tx_xadd.3 tx_xadd_field.3 tx_xadd_direct.3 tx_xadd_field_direct.3 \ tx_new.3 tx_alloc.3 tx_znew.3 tx_zalloc.3 tx_xalloc.3 tx_realloc.3 tx_zrealloc.3 tx_strdup.3 tx_wcsdup.3 tx_free.3 tx_set.3 tx_set_direct.3 tx_memcpy.3 tx_memset.3 \ pmemobj_mutex_lock.3 pmemobj_mutex_timedlock.3 pmemobj_mutex_trylock.3 pmemobj_mutex_unlock.3 \ pmemobj_rwlock_zero.3 pmemobj_rwlock_rdlock.3 pmemobj_rwlock_wrlock.3 pmemobj_rwlock_timedrdlock.3 pmemobj_rwlock_timedwrlock.3 pmemobj_rwlock_tryrdlock.3 pmemobj_rwlock_trywrlock.3 pmemobj_rwlock_unlock.3 \ pmemobj_cond_zero.3 pmemobj_cond_broadcast.3 pmemobj_cond_signal.3 pmemobj_cond_timedwait.3 pmemobj_cond_wait.3 \ pobj_list_entry.3 pobj_list_first.3 pobj_list_last.3 pobj_list_empty.3 pobj_list_next.3 pobj_list_prev.3 pobj_list_foreach.3 pobj_list_foreach_reverse.3 \ pobj_list_insert_head.3 pobj_list_insert_tail.3 pobj_list_insert_after.3 pobj_list_insert_before.3 pobj_list_insert_new_head.3 pobj_list_insert_new_tail.3 \ pobj_list_insert_new_after.3 pobj_list_insert_new_before.3 pobj_list_remove.3 pobj_list_remove_free.3 \ pobj_list_move_element_head.3 pobj_list_move_element_tail.3 pobj_list_move_element_after.3 pobj_list_move_element_before.3 \ pmemobj_next.3 pobj_first_type_num.3 pobj_first.3 pobj_next_type_num.3 pobj_next.3 pobj_foreach.3 pobj_foreach_safe.3 pobj_foreach_type.3 pobj_foreach_safe_type.3 \ pmemobj_root_construct.3 pobj_root.3 pmemobj_root_size.3 \ pmemobj_check_version.3 pmemobj_check.3 pmemobj_errormsg.3 pmemobj_set_funcs.3 \ pmemobj_reserve.3 pmemobj_xreserve.3 pmemobj_set_value.3 pmemobj_publish.3 pmemobj_tx_publish.3 pmemobj_cancel.3 pobj_reserve_new.3 pobj_reserve_alloc.3 \ pmemcto_close.3 pmemcto_create.3 \ pmemcto_check.3 \ pmemcto_calloc.3 pmemcto_realloc.3 pmemcto_free.3 \ pmemcto_get_root_pointer.3 \ pmemcto_check_version.3 pmemcto_set_funcs.3 pmemcto_errormsg.3 MANPAGES_BUILDDIR = generated MANPAGES_WEBDIR_LINUX = web_linux MANPAGES_WEBDIR_WINDOWS = web_windows # experimental MANPAGES_3_MD_EXP = MANPAGES_1_MD_EXP = MANPAGES_3_MD_DUMMY_EXP = MANPAGES_1_MD_DUMMY_EXP = ifeq ($(BUILD_RPMEM),y) MANPAGES_7_MD += librpmem/librpmem.7.md MANPAGES_3_MD += librpmem/rpmem_create.3.md MANPAGES_3_MD += librpmem/rpmem_persist.3.md MANPAGES_1_MD += rpmemd/rpmemd.1.md MANPAGES_3_DUMMY += rpmem_open.3 rpmem_set_attr.3 rpmem_close.3 \ rpmem_read.3 rpmem_remove.3 rpmem_check_version.3 \ rpmem_errormsg.3 rpmem_deep_persist.3 endif ifeq ($(NDCTL_ENABLE),y) MANPAGES_1_MD += daxio/daxio.1.md endif MANPAGES_7_GROFF = $(MANPAGES_7_MD:.7.md=.7) MANPAGES_5_GROFF = $(MANPAGES_5_MD:.5.md=.5) MANPAGES_3_GROFF = $(MANPAGES_3_MD:.3.md=.3) MANPAGES_1_GROFF = $(MANPAGES_1_MD:.1.md=.1) MANPAGES_7_GROFF_EXP = $(MANPAGES_7_MD_EXP:.3.md=.7) MANPAGES_5_GROFF_EXP = $(MANPAGES_5_MD_EXP:.3.md=.5) MANPAGES_3_GROFF_EXP = $(MANPAGES_3_MD_EXP:.3.md=.3) MANPAGES_1_GROFF_EXP = $(MANPAGES_1_MD_EXP:.1.md=.1) ifeq ($(EXPERIMENTAL),y) $(MANPAGES_7_GROFF) += $(MANPAGES_7_GROFF_EXP) $(MANPAGES_5_GROFF) += $(MANPAGES_5_GROFF_EXP) $(MANPAGES_3_GROFF) += $(MANPAGES_3_GROFF_EXP) $(MANPAGES_1_GROFF) += $(MANPAGES_1_GROFF_EXP) else MANPAGES_7_NOINSTALL += $(MANPAGES_7_GROFF_EXP) MANPAGES_5_NOINSTALL += $(MANPAGES_5_GROFF_EXP) MANPAGES_3_NOINSTALL += $(MANPAGES_3_GROFF_EXP) MANPAGES_1_NOINSTALL += $(MANPAGES_1_GROFF_EXP) endif MANPAGES = $(MANPAGES_7_GROFF) $(MANPAGES_5_GROFF) $(MANPAGES_3_GROFF) $(MANPAGES_1_GROFF) \ $(MANPAGES_7_NOINSTALL) $(MANPAGES_5_NOINSTALL) $(MANPAGES_3_NOINSTALL) $(MANPAGES_1_NOINSTALL) MANPAGES_BUILD = $(addprefix $(MANPAGES_BUILDDIR)/, $(notdir $(MANPAGES))) HTMLFILES = $(MANPAGES_BUILD:=.html) TXTFILES = $(MANPAGES_BUILD:=.txt) GZFILES_7 = $(MANPAGES_7_GROFF:=.gz) GZFILES_5 = $(MANPAGES_5_GROFF:=.gz) GZFILES_3 = $(MANPAGES_3_GROFF:=.gz) GZFILES_1 = $(MANPAGES_1_GROFF:=.gz) GZFILES_7_NOINSTALL = $(MANPAGES_7_NOINSTALL:=.gz) GZFILES_5_NOINSTALL = $(MANPAGES_5_NOINSTALL:=.gz) GZFILES_3_NOINSTALL = $(MANPAGES_3_NOINSTALL:=.gz) GZFILES_1_NOINSTALL = $(MANPAGES_1_NOINSTALL:=.gz) GZFILES_3_DUMMY = $(MANPAGES_3_DUMMY:=.gz) GZFILES = $(GZFILES_7) $(GZFILES_5) $(GZFILES_3) $(GZFILES_1) \ $(GZFILES_7_NOINSTALL) $(GZFILES_5_NOINSTALL) $(GZFILES_3_NOINSTALL) $(GZFILES_1_NOINSTALL) \ $(GZFILES_3_DUMMY) GZFILES_BUILD = $(addprefix $(MANPAGES_BUILDDIR)/, $(notdir $(GZFILES))) GZFILES_7_BUILD = $(addprefix $(MANPAGES_BUILDDIR)/, $(notdir $(GZFILES_7))) GZFILES_5_BUILD = $(addprefix $(MANPAGES_BUILDDIR)/, $(notdir $(GZFILES_5))) GZFILES_3_BUILD = $(addprefix $(MANPAGES_BUILDDIR)/, $(notdir $(GZFILES_3))) GZFILES_1_BUILD = $(addprefix $(MANPAGES_BUILDDIR)/, $(notdir $(GZFILES_1))) GZFILES_3_BUILD += $(addprefix $(MANPAGES_BUILDDIR)/, $(GZFILES_3_DUMMY)) DOXYGEN_HTMLDIR=cpp_html MANPAGES_DESTDIR_7 = $(DESTDIR)$(man7dir) MANPAGES_DESTDIR_5 = $(DESTDIR)$(man5dir) MANPAGES_DESTDIR_3 = $(DESTDIR)$(man3dir) MANPAGES_DESTDIR_1 = $(DESTDIR)$(man1dir) DOCS_DESTDIR = $(DESTDIR)$(docdir) CPP_DOC_DIR ?= libpmemobj++-dev CPP_DOCS_DESTDIR = $(DOCS_DESTDIR)/$(CPP_DOC_DIR) all: md2man $(TXTFILES) doxygen_docs | $(MANPAGES_BUILDDIR) $(MANPAGES_BUILDDIR) $(MANPAGES_WEBDIR_LINUX) $(MANPAGES_WEBDIR_WINDOWS): $(MKDIR) -p $@ %.txt: % man ./$< > $@ groff: $(MANPAGES_7_GROFF) $(MANPAGES_5_GROFF) $(MANPAGES_3_GROFF) $(MANPAGES_1_GROFF) doxygen_docs: doxygen cppobj.Doxyfile html: $(HTMLFILES) doxygen_docs %.html: % groff -mandoc -Thtml ./$< > $@ md2man: $(foreach f, $(MANPAGES_7_MD), ../utils/md2man.sh $(f) default.man $(MANPAGES_BUILDDIR)/$(basename $(notdir $(f)));) $(foreach f, $(MANPAGES_5_MD), ../utils/md2man.sh $(f) default.man $(MANPAGES_BUILDDIR)/$(basename $(notdir $(f)));) $(foreach f, $(MANPAGES_3_MD), ../utils/md2man.sh $(f) default.man $(MANPAGES_BUILDDIR)/$(basename $(notdir $(f)));) $(foreach f, $(MANPAGES_1_MD), ../utils/md2man.sh $(f) default.man $(MANPAGES_BUILDDIR)/$(basename $(notdir $(f)));) web: | $(MANPAGES_WEBDIR_LINUX) $(MANPAGES_WEBDIR_WINDOWS) $(MAKE) -C generated all $(foreach f, $(MANPAGES_7_MD), WEB=1 WIN32="" ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_LINUX)/$(f);) $(foreach f, $(MANPAGES_5_MD), WEB=1 WIN32="" ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_LINUX)/$(f);) $(foreach f, $(MANPAGES_3_MD), WEB=1 WIN32="" ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_LINUX)/$(f);) $(foreach f, $(MANPAGES_1_MD), WEB=1 WIN32="" ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_LINUX)/$(f);) $(foreach f, $(MANPAGES_7_MD), WEB=1 WIN32=1 ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_WINDOWS)/$(f);) $(foreach f, $(MANPAGES_5_MD), WEB=1 WIN32=1 ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_WINDOWS)/$(f);) $(foreach f, $(MANPAGES_3_MD), WEB=1 WIN32=1 ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_WINDOWS)/$(f);) $(foreach f, $(MANPAGES_1_MD), WEB=1 WIN32=1 ../utils/md2man.sh $(f) default.man $(MANPAGES_WEBDIR_WINDOWS)/$(f);) compress: $(GZFILES_BUILD) %.gz: gzip -c ./$* > $@ clean: clobber: clean $(RM) -rf $(DOXYGEN_HTMLDIR) \ $(MANPAGES_BUILDDIR)/*.txt \ $(MANPAGES_BUILDDIR)/*.html \ $(MANPAGES_BUILDDIR)/*.gz \ $(MANPAGES_WEBDIR_LINUX) \ $(MANPAGES_WEBDIR_WINDOWS) install-cpp: doxygen_docs $(call install_recursive,$(DOXYGEN_HTMLDIR),0644,$(CPP_DOCS_DESTDIR)) install: install-cpp uninstall-cpp: $(RM) -rf $(CPP_DOCS_DESTDIR) uninstall: uninstall-cpp install: compress install -d -v $(MANPAGES_DESTDIR_7) install -p -m 0644 $(GZFILES_7_BUILD) $(MANPAGES_DESTDIR_7) install -d -v $(MANPAGES_DESTDIR_5) install -p -m 0644 $(GZFILES_5_BUILD) $(MANPAGES_DESTDIR_5) install -d -v $(MANPAGES_DESTDIR_3) install -p -m 0644 $(GZFILES_3_BUILD) $(MANPAGES_DESTDIR_3) install -d -v $(MANPAGES_DESTDIR_1) install -p -m 0644 $(GZFILES_1_BUILD) $(MANPAGES_DESTDIR_1) uninstall: $(foreach f, $(notdir $(GZFILES_7_BUILD)), $(RM) $(MANPAGES_DESTDIR_7)/$(f)) $(foreach f, $(notdir $(GZFILES_5_BUILD)), $(RM) $(MANPAGES_DESTDIR_5)/$(f)) $(foreach f, $(notdir $(GZFILES_3_BUILD)), $(RM) $(MANPAGES_DESTDIR_3)/$(f)) $(foreach f, $(notdir $(GZFILES_1_BUILD)), $(RM) $(MANPAGES_DESTDIR_1)/$(f)) FORCE: .PHONY: all html clean compress clobber cstyle install uninstall install-cpp\ uninstall-cpp doxygen_docs pmdk-1.4.1/doc/README000066400000000000000000000051471331545616200141120ustar00rootroot00000000000000Persistent Memory Development Kit This is doc/README. Subdirectories of this directory contain source for the man pages for the Persistent Memory Development Kit in markdown format (.md files). If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. Developers new to PMDK are probably looking for libpmemobj. To generate web-based documentation or Linux/FreeBSD man pages, you need to have groff, doxygen and pandoc installed. m4 macros are used in the document sources to generate OS-specific variants of man pages and web-based documentation. The macros are defined in macros.man. Processing is performed by the ../utils/md2man.sh script. All files in the *generated* directory are automatically generated and updated by the pmdk-bot. **DO NOT MODIFY THE FILES IN THAT DIRECTORY**. All changes to the documentation must be made by modifying the *.md files in the following document subdirectories: libpmem -- low-level persistent memory support libpmemblk -- pmem-resident arrays of blocks libpmemlog -- pmem-resident log files libpmemobj -- transactional object store libpmemcto -- close-to-open persistence (EXPERIMENTAL) libvmem -- volatile memory allocation library libvmmalloc -- general purpose volatile memory allocation library libpmempool -- persistent memory pool management library pmempool -- Persistent Memory Pool Management Tool librpmem -- remote access to persistent memory (EXPERIMENTAL) rpmemd -- remote persistent memory daemon (EXPERIMENTAL) daxio -- perform I/O on Device DAX device These man pages provide the API specification for the corresponding libraries and commands in this source tree, so any updates to one should be tested, reviewed, and committed with changes to the other. To create more readable text files from the source, use: $ [g]make NOTE: This will write man page output into the *generated* subdirectory. Files in this directory MUST NOT be included in any pull requests. The man(1) command may be used to format generated man pages for viewing in a terminal window (includes bold, underline, etc.), for example: $ man generated/libpmem.7 $ man generated/pmemobj_create.3 In addition, for testing purposes ../utils/md2man.sh will generate a preprocessed markdown file with the headers stripped off if the TESTOPTS variable is set. For example: $ export TESTOPTS="-DWIN32 -UFREEBSD -UWEB" $ ../utils/md2man.sh libpmemobj/libpmemobj.7.md x libpmemobj.7.win.md will generate a version of the libpmemobj.7 man page for Windows in markdown format. The resulting file may be viewed with a markdown-enabled browser. pmdk-1.4.1/doc/cppobj.Doxyfile000066400000000000000000000225041331545616200162100ustar00rootroot00000000000000#--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "PMDK C++ bindings" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = "1.2.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "This is the C++ bindings documentation for PMDK's libpmemobj." # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = YES # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. QUIET = YES #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = ../src/include/libpmemobj++ INPUT += ../src/include/libpmemobj++/README.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.hpp # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = ../src/examples/libpmemobj++/doc_snippets # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to strip. # Note that you can specify absolute paths here, but also relative paths, which will # be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = ../.. # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name # of the header file containing the class definition is used. Otherwise one # should specify the list of include paths that are normally passed to the # compiler using the -I flag. STRIP_FROM_INC_PATH = ../src/include/ #--------------------------------------------------------------------------- # Configuration options related to the LATEX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES doxygen will generate LATEX output # The default value is: YES. GENERATE_LATEX = NO #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = cpp_html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. # gcc). The argument of the tag is a list of macros of the form: name or # name=definition (no spaces). If the definition and the "=" are omitted, "=1" # is assumed. To prevent a macro definition from being undefined via #undef or # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = __cpp_lib_uncaught_exceptions _WIN32 pmdk-1.4.1/doc/daxio/000077500000000000000000000000001331545616200143275ustar00rootroot00000000000000pmdk-1.4.1/doc/daxio/daxio.1.md000066400000000000000000000107431331545616200161210ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(DAXIO, 1) collection: daxio header: PMDK date: daxio version 1.4 ... [comment]: <> (Copyright 2018, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (daxio.1 -- man page for daxio) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[OPTIONS](#options)
[EXAMPLE](#commands)
[SEE ALSO](#see-also)
# NAME # **daxio** -- Perform I/O on Device DAX devices or zero a Device DAX device # SYNOPSIS # ``` $ daxio [] ``` # DESCRIPTION # The daxio utility performs I/O on Device DAX devices or zero a Device DAX device. Since the standard I/O APIs (read/write) cannot be used with Device DAX, data transfer is performed on a memory-mapped device. The **daxio** may be used to dump Device DAX data to a file, restore data from a backup copy, move/copy data to another device or to erase data from a device. There must be at least one Device DAX device involved either as the input or output. If input or output is not specified, it will default to stdin or stdout respectively. No length specified will default to input file/device length or to the output file/device length, if input is a special char file or stdin. For a Device DAX device, **daxio** will attempts to clear badblocks within range of writes before performing the I/O. # OPTIONS # `-i, --input` Input device or file to read from. `-o, --output` Output device or file to write to. `-z, --zero` Zero the output device for *len* size, or the entire device if no length was provided. The output device must be a Device DAX device. `-l, --len` The length in bytes to perform the I/O. To make passing in size easier for kibi, mebi, gibi, and tebi bytes, *len* may include unit suffix. The *len* format must be compliant with the format specified in IEC 80000-13, IEEE 1541 or the Metric Interchange Format. These standards accept SI units with obligatory B - kB, MB, GB, ... (multiplier by 1000) suffixes, and IEC units with optional "iB" - KiB, MiB, GiB, ..., K, M, G, ... (multiplier by 1024) suffixes. `-s, --seek` The number of bytes to skip over on the output before performing a write. The same suffixes are accepted as for *len*. `-k, --skip` The number of bytes to skip over on the input before performing a read. The same suffixes are accepted as for *len*. `-V, --version` Prints the version of **daxio**. `-h, --help` Prints synopsis and list of options. # EXAMPLE # ``` # daxio --zero /dev/dax1.0 # daxio --input=/dev/dax1.0 --output=/home/myfile --len=2M --seek=4096 # cat /dev/zero | daxio --output=/dev/dax1.0 # daxio --input=/dev/zero --output=/dev/dax1.0 --skip=4096 ``` # SEE ALSO # **daxctl**(1), **ndctl**(1) and **** pmdk-1.4.1/doc/default.man000066400000000000000000000041611331545616200153460ustar00rootroot00000000000000$if(has-tables)$ .\"t $endif$ $if(pandoc-version)$ .\" Automatically generated by Pandoc $pandoc-version$ .\" $endif$ $if(adjusting)$ .ad $adjusting$ $endif$ .TH "$title$" "$section$" "$date$" "PMDK - $version$" "PMDK Programmer's Manual" $if(hyphenate)$ .hy $else$ .nh \" Turn off hyphenation by default. $endif$ $for(header-includes)$ $header-includes$ $endfor$ .\" Copyright 2014-$year$, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. $for(include-before)$ $include-before$ $endfor$ $body$ $for(include-after)$ $include-after$ $endfor$ $if(author)$ .SH AUTHORS $for(author)$$author$$sep$; $endfor$. $endif$ pmdk-1.4.1/doc/generated/000077500000000000000000000000001331545616200151615ustar00rootroot00000000000000pmdk-1.4.1/doc/generated/.gitignore000066400000000000000000000000061331545616200171450ustar00rootroot00000000000000*.yml pmdk-1.4.1/doc/generated/Makefile000066400000000000000000000032451331545616200166250ustar00rootroot00000000000000# # Copyright 2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # generated/Makefile -- Makefile for generate pmem.io aliases map # all: ../../utils/get_aliases.sh clean: $(RM) -rf libs_map.yml pmdk-1.4.1/doc/generated/d_ro.3000066400000000000000000000000231331545616200161630ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/d_rw.3000066400000000000000000000000231331545616200161730ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/daxio.1000066400000000000000000000104301331545616200163450ustar00rootroot00000000000000.\" Automatically generated by Pandoc 1.17.0.3 .\" .TH "DAXIO" "1" "2018-03-07" "PMDK - daxio version 1.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]daxio\f[] \-\- Perform I/O on Device DAX devices or zero a Device DAX device .SH SYNOPSIS .IP .nf \f[C] $\ daxio\ [] \f[] .fi .SH DESCRIPTION .PP The daxio utility performs I/O on Device DAX devices or zero a Device DAX device. Since the standard I/O APIs (read/write) cannot be used with Device DAX, data transfer is performed on a memory\-mapped device. The \f[B]daxio\f[] may be used to dump Device DAX data to a file, restore data from a backup copy, move/copy data to another device or to erase data from a device. .PP There must be at least one Device DAX device involved either as the input or output. If input or output is not specified, it will default to stdin or stdout respectively. .PP No length specified will default to input file/device length or to the output file/device length, if input is a special char file or stdin. .PP For a Device DAX device, \f[B]daxio\f[] will attempts to clear badblocks within range of writes before performing the I/O. .SH OPTIONS .PP \f[C]\-i,\ \-\-input\f[] Input device or file to read from. .PP \f[C]\-o,\ \-\-output\f[] Output device or file to write to. .PP \f[C]\-z,\ \-\-zero\f[] Zero the output device for \f[I]len\f[] size, or the entire device if no length was provided. The output device must be a Device DAX device. .PP \f[C]\-l,\ \-\-len\f[] The length in bytes to perform the I/O. To make passing in size easier for kibi, mebi, gibi, and tebi bytes, \f[I]len\f[] may include unit suffix. The \f[I]len\f[] format must be compliant with the format specified in IEC 80000\-13, IEEE 1541 or the Metric Interchange Format. These standards accept SI units with obligatory B \- kB, MB, GB, ... (multiplier by 1000) suffixes, and IEC units with optional "iB" \- KiB, MiB, GiB, ..., K, M, G, ... (multiplier by 1024) suffixes. .PP \f[C]\-s,\ \-\-seek\f[] The number of bytes to skip over on the output before performing a write. The same suffixes are accepted as for \f[I]len\f[]. .PP \f[C]\-k,\ \-\-skip\f[] The number of bytes to skip over on the input before performing a read. The same suffixes are accepted as for \f[I]len\f[]. .PP \f[C]\-V,\ \-\-version\f[] .PP Prints the version of \f[B]daxio\f[]. .PP \f[C]\-h,\ \-\-help\f[] .PP Prints synopsis and list of options. .SH EXAMPLE .IP .nf \f[C] #\ daxio\ \-\-zero\ /dev/dax1.0 #\ daxio\ \-\-input=/dev/dax1.0\ \-\-output=/home/myfile\ \-\-len=2M\ \-\-seek=4096 #\ cat\ /dev/zero\ |\ daxio\ \-\-output=/dev/dax1.0 #\ daxio\ \-\-input=/dev/zero\ \-\-output=/dev/dax1.0\ \-\-skip=4096 \f[] .fi .SH SEE ALSO .PP \f[B]daxctl\f[](1), \f[B]ndctl\f[](1) and \f[B]\f[] pmdk-1.4.1/doc/generated/direct_ro.3000066400000000000000000000000231331545616200172120ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/direct_rw.3000066400000000000000000000000231331545616200172220ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/libpmem.7000066400000000000000000000370411331545616200167030ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBPMEM" "7" "2018-05-21" "PMDK - pmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libpmem\f[] \[en] persistent memory support library .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ ...\ \-lpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *pmem_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *pmem_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libpmem\f[] functions can be found on the following manual pages: .IP \[bu] 2 most commonly used functions: \f[B]pmem_is_pmem\f[](3) .IP \[bu] 2 partial flushing operations: \f[B]pmem_flush\f[](3) .IP \[bu] 2 copying to persistent memory: \f[B]pmem_memmove_persist\f[](3) .SH DESCRIPTION .PP \f[B]libpmem\f[] provides low\-level \f[I]persistent memory\f[] (pmem) support for applications using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of \f[I]non\-volatile memory DIMMs\f[] (NVDIMMs) provide this type of byte addressable access to storage. A \f[I]persistent memory aware file system\f[] is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in the load/store, non\-paged access to pmem. .PP This library is for applications that use persistent memory directly, without the help of any library\-supplied transactions or memory allocation. Higher\-level libraries that build on \f[B]libpmem\f[] are available and are recommended for most applications, see: .IP \[bu] 2 \f[B]libpmemobj\f[](7), a general use persistent memory API, providing memory allocation and transactional operations on variable\-sized objects. .IP \[bu] 2 \f[B]libpmemblk\f[](7), providing pmem\-resident arrays of fixed\-sized blocks with atomic updates. .IP \[bu] 2 \f[B]libpmemlog\f[](7), providing a pmem\-resident log file. .PP Under normal usage, \f[B]libpmem\f[] will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under \f[B]DEBUGGING AND ERROR HANDLING\f[] below. .SH CAVEATS .PP \f[B]libpmem\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]pmem_check_version\f[]() function is used to determine whether the installed \f[B]libpmem\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ pmem_check_version(PMEM_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEM_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP When the version check performed by \f[B]pmem_check_version\f[]() is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by \f[B]pmem_check_version\f[]() must not be modified or freed. .SH ENVIRONMENT .PP \f[B]libpmem\f[] can change its default behavior based on the following environment variables. These are largely intended for testing and are not normally required. .IP \[bu] 2 \f[B]PMEM_IS_PMEM_FORCE\f[]=\f[I]val\f[] .PP If \f[I]val\f[] is 0 (zero), then \f[B]pmem_is_pmem\f[](3) will always return false. Setting \f[I]val\f[] to 1 causes \f[B]pmem_is_pmem\f[](3) to always return true. This variable is mostly used for testing but can be used to force pmem behavior on a system where a range of pmem is not detectable as pmem for some reason. .RS .PP NOTE: Unlike the other variables, the value of \f[B]PMEM_IS_PMEM_FORCE\f[] is not queried (and cached) at library initialization time, but on the first call to \f[B]pmem_is_pmem\f[](3). This means that in case of \f[B]libpmemlog\f[](7), \f[B]libpmemblk\f[](7), and \f[B]libpmemobj\f[](7), \f[B]PMEM_IS_PMEM_FORCE\f[] may still be set or modified by the program until the first attempt to create or open the persistent memory pool. .RE .IP \[bu] 2 \f[B]PMEM_NO_CLWB\f[]=1 .PP Setting this environment variable to 1 forces \f[B]libpmem\f[] to never issue the \f[B]CLWB\f[] instruction on Intel hardware, falling back to other cache flush instructions instead (\f[B]CLFLUSHOPT\f[] or \f[B]CLFLUSH\f[] on Intel hardware). Without this environment variable, \f[B]libpmem\f[] will always use the \f[B]CLWB\f[] instruction for flushing processor caches on platforms that support the instruction. This variable is intended for use during library testing but may be required for some rare cases where using \f[B]CLWB\f[] has a negative impact on performance. .IP \[bu] 2 \f[B]PMEM_NO_CLFLUSHOPT\f[]=1 .PP Setting this environment variable to 1 forces \f[B]libpmem\f[] to never issue the \f[B]CLFLUSHOPT\f[] instruction on Intel hardware, falling back to the \f[B]CLFLUSH\f[] instructions instead. Without this environment variable, \f[B]libpmem\f[] will always use the \f[B]CLFLUSHOPT\f[] instruction for flushing processor caches on platforms that support the instruction, but where \f[B]CLWB\f[] is not available. This variable is intended for use during library testing. .IP \[bu] 2 \f[B]PMEM_NO_FLUSH\f[]=1 .PP Setting this environment variable to 1 forces most \f[B]libpmem\f[] functions to never issue any of \f[B]CLFLUSH\f[], \f[B]CLFLUSHOPT\f[] or \f[B]CLWB\f[] instructions on Intel hardware. The only exceptions are \f[B]pmem_deep_flush\f[](3) and \f[B]pmem_deep_persist\f[](3) functions. .IP \[bu] 2 \f[B]PMEM_NO_FLUSH\f[]=0 .PP Setting this environment variable to 0 forces to always flush CPU caches using one of \f[B]CLFLUSH\f[], \f[B]CLFLUSHOPT\f[] or \f[B]CLWB\f[] instructions even if \f[B]pmem_has_auto_flush\f[](3) function returns true and the platform supports flushing the processor caches on power loss or system crash. .IP \[bu] 2 \f[B]PMEM_NO_MOVNT\f[]=1 .PP Setting this environment variable to 1 forces \f[B]libpmem\f[] to never use the \f[I]non\-temporal\f[] move instructions on Intel hardware. Without this environment variable, \f[B]libpmem\f[] will use the non\-temporal instructions for copying larger ranges to persistent memory on platforms that support the instructions. This variable is intended for use during library testing. .IP \[bu] 2 \f[B]PMEM_MOVNT_THRESHOLD\f[]=\f[I]val\f[] .PP This environment variable allows overriding the minimum length of the \f[B]pmem_memmove_persist\f[](3) operations, for which \f[B]libpmem\f[] uses \f[I]non\-temporal\f[] move instructions. Setting this environment variable to 0 forces \f[B]libpmem\f[] to always use the \f[I]non\-temporal\f[] move instructions if available. It has no effect if \f[B]PMEM_NO_MOVNT\f[] is set to 1. This variable is intended for use during library testing. .IP \[bu] 2 \f[B]PMEM_MMAP_HINT\f[]=\f[I]val\f[] .PP This environment variable allows overriding the hint address used by \f[B]pmem_map_file\f[](). If set, it also disables mapping address randomization. This variable is intended for use during library testing and debugging. Setting it to some fairly large value (i.e.\ 0x10000000000) will very likely result in mapping the file at the specified address (if not used) or at the first unused region above given address, without adding any random offset. When debugging, this makes it easier to calculate the actual address of the persistent memory block, based on its offset in the file. In case of \f[B]libpmemobj\f[] it simplifies conversion of a persistent object identifier (OID) into a direct pointer to the object. .RS .PP NOTE: \f[B]Setting this environment variable affects all the PMDK libraries,\f[] disabling mapping address randomization and causing the specified address to be used as a hint about where to place the mapping. .RE .SH DEBUGGING AND ERROR HANDLING .PP If an error is detected during the call to a \f[B]libpmem\f[] function, the application may retrieve an error message describing the reason for the failure from \f[B]pmem_errormsg\f[](). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libpmem\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libpmem\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lpmem\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. .PP A second version of \f[B]libpmem\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the environment variable \f[B]LD_LIBRARY_PATH\f[] to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]PMEM_LOG_LEVEL\f[] .PP The value of \f[B]PMEM_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]PMEM_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. The same information may be retrieved using \f[B]pmem_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]libpmem\f[] developers. .PP Unless \f[B]PMEM_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]PMEM_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]PMEM_LOG_FILE\f[] is not set, output is written to \f[I]stderr\f[]. .SH EXAMPLE .PP The following example uses \f[B]libpmem\f[] to flush changes made to raw, memory\-mapped persistent memory. .RS .PP WARNING: There is nothing transactional about the \f[B]pmem_persist\f[](3) or \f[B]pmem_msync\f[](3) calls in this example. Interrupting the program may result in a partial write to pmem. Use a transactional library such as \f[B]libpmemobj\f[](7) to avoid torn updates. .RE .IP .nf \f[C] #include\ #include\ #include\ #include\ #include\ #include\ #include\ #include\ #include\ /*\ using\ 4k\ of\ pmem\ for\ this\ example\ */ #define\ PMEM_LEN\ 4096 #define\ PATH\ "/pmem\-fs/myfile" int main(int\ argc,\ char\ *argv[]) { \ \ \ \ char\ *pmemaddr; \ \ \ \ size_t\ mapped_len; \ \ \ \ int\ is_pmem; \ \ \ \ /*\ create\ a\ pmem\ file\ and\ memory\ map\ it\ */ \ \ \ \ if\ ((pmemaddr\ =\ pmem_map_file(PATH,\ PMEM_LEN,\ PMEM_FILE_CREATE, \ \ \ \ \ \ \ \ \ \ \ \ 0666,\ &mapped_len,\ &is_pmem))\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror("pmem_map_file"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ store\ a\ string\ to\ the\ persistent\ memory\ */ \ \ \ \ strcpy(pmemaddr,\ "hello,\ persistent\ memory"); \ \ \ \ /*\ flush\ above\ strcpy\ to\ persistence\ */ \ \ \ \ if\ (is_pmem) \ \ \ \ \ \ \ \ pmem_persist(pmemaddr,\ mapped_len); \ \ \ \ else \ \ \ \ \ \ \ \ pmem_msync(pmemaddr,\ mapped_len); \ \ \ \ /* \ \ \ \ \ *\ Delete\ the\ mappings.\ The\ region\ is\ also \ \ \ \ \ *\ automatically\ unmapped\ when\ the\ process\ is \ \ \ \ \ *\ terminated. \ \ \ \ \ */ \ \ \ \ pmem_unmap(pmemaddr,\ mapped_len); } \f[] .fi .PP See for more examples using the \f[B]libpmem\f[] API. .SH ACKNOWLEDGEMENTS .PP \f[B]libpmem\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]dlclose\f[](3), \f[B]pmem_flush\f[](3), \f[B]pmem_is_pmem\f[](3), \f[B]pmem_memmove_persist\f[](3), \f[B]pmem_msync\f[](3), \f[B]pmem_persist\f[](3), \f[B]strerror\f[](3), \f[B]libpmemblk\f[](7), \f[B]libpmemcto\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/libpmemblk.7000066400000000000000000000325031331545616200173720ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBPMEMBLK" "7" "2018-05-21" "PMDK - pmemblk API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libpmemblk\f[] \[en] persistent memory resident array of blocks .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ ...\ \-lpmemblk\ \-lpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *pmemblk_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Managing library behavior: .IP .nf \f[C] void\ pmemblk_set_funcs( \ \ \ \ void\ *(*malloc_func)(size_t\ size), \ \ \ \ void\ (*free_func)(void\ *ptr), \ \ \ \ void\ *(*realloc_func)(void\ *ptr,\ size_t\ size), \ \ \ \ char\ *(*strdup_func)(const\ char\ *s)); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *pmemblk_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libpmemblk\f[] functions can be found on the following manual pages: .PP \f[B]pmemblk_create\f[](3), \f[B]pmemblk_bsize\f[](3), \f[B]pmemblk_read\f[](3), \f[B]pmemblk_set_zero\f[](3) .SH DESCRIPTION .PP \f[B]libpmemblk\f[] provides an array of blocks in \f[I]persistent memory\f[] (pmem) such that updates to a single block are atomic. This library is intended for applications using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of \f[I]non\-volatile memory DIMMs\f[] (NVDIMMs) provide this type of byte addressable access to storage. A \f[I]persistent memory aware file system\f[] is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in the load/store, non\-paged access to pmem. \f[B]libpmemblk\f[] builds on this type of memory mapped file. .PP This library is for applications that need a potentially large array of blocks, all the same size, where any given block is updated atomically (the update cannot be \f[I]torn\f[] by program interruption such as power failures). This library builds on the low\-level pmem support provided by \f[B]libpmem\f[](3), handling the transactional update of the blocks, flushing to persistence, and recovery for the application. \f[B]libpmemblk\f[] is one of a collection of persistent memory libraries available, the others are: .IP \[bu] 2 \f[B]libpmemobj\f[](7), a general use persistent memory API, providing memory allocation and transactional operations on variable\-sized objects. .IP \[bu] 2 \f[B]libpmemlog\f[](7), providing a pmem\-resident log file. .IP \[bu] 2 \f[B]libpmemcto\f[](7), providing close\-to\-open persistence. .IP \[bu] 2 \f[B]libpmem\f[](7), low\-level persistent memory support. .PP Under normal usage, \f[B]libpmemblk\f[] will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under \f[B]DEBUGGING AND ERROR HANDLING\f[] below. .PP To use the atomic block arrays supplied by \f[B]libpmemblk\f[], a \f[I]memory pool\f[] is first created using the \f[B]pmemblk_create\f[]() function described in \f[B]pmemblk_create\f[](3). The other \f[B]libpmemblk\f[] functions operate on the resulting block memory pool using the opaque handle, of type \f[I]PMEMblkpool*\f[], that is returned by \f[B]pmemblk_create\f[]() or \f[B]pmemblk_open\f[](). Internally, \f[B]libpmemblk\f[] will use either \f[B]pmem_persist\f[](3) or \f[B]msync\f[](2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the \f[B]pmem_is_pmem\f[](3) function in \f[B]libpmem\f[](7) for more information). There is no need for applications to flush changes directly when using the block memory API provided by \f[B]libpmemblk\f[]. .SH CAVEATS .PP \f[B]libpmemblk\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]pmemblk_check_version\f[]() function is used to determine whether the installed \f[B]libpmemblk\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ pmemblk_check_version(PMEMBLK_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEMBLK_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP When the version check performed by \f[B]pmemblk_check_version\f[]() is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by \f[B]pmemblk_check_version\f[]() must not be modified or freed. .SH MANAGING LIBRARY BEHAVIOR .PP The \f[B]pmemblk_set_funcs\f[]() function allows an application to override memory allocation calls used internally by \f[B]libpmemblk\f[]. Passing in NULL for any of the handlers will cause the \f[B]libpmemblk\f[] default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4\-8 kilobytes for each memory pool in use. .SH DEBUGGING AND ERROR HANDLING .PP The \f[B]pmemblk_errormsg\f[]() function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code, as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libpmemblk\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libpmemblk\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lpmemblk\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. If an error is detected in a call to \f[B]libpmemblk\f[], the error message describing the failure may be retrieved with \f[B]pmemblk_errormsg\f[]() as described above. .PP A second version of \f[B]libpmemblk\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the \f[B]LD_LIBRARY_PATH\f[] environment variable to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]PMEMBLK_LOG_LEVEL\f[] .PP The value of \f[B]PMEMBLK_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]PMEMBLK_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. The same information may be retrieved using \f[B]pmemblk_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]libpmemblk\f[] developers. .PP Unless \f[B]PMEMBLK_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]PMEMBLK_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]PMEMBLK_LOG_FILE\f[] is not set, the logging output is written to \f[I]stderr\f[]. .PP See also \f[B]libpmem\f[](7) for information on other environment variables that may affect \f[B]libpmemblk\f[] behavior. .SH EXAMPLE .PP The following example illustrates how the \f[B]libpmemblk\f[] API is used. .IP .nf \f[C] #include\ #include\ #include\ #include\ #include\ #include\ /*\ size\ of\ the\ pmemblk\ pool\ \-\-\ 1\ GB\ */ #define\ POOL_SIZE\ ((size_t)(1\ <<\ 30)) /*\ size\ of\ each\ element\ in\ the\ pmem\ pool\ */ #define\ ELEMENT_SIZE\ 1024 int main(int\ argc,\ char\ *argv[]) { \ \ \ \ const\ char\ path[]\ =\ "/pmem\-fs/myfile"; \ \ \ \ PMEMblkpool\ *pbp; \ \ \ \ size_t\ nelements; \ \ \ \ char\ buf[ELEMENT_SIZE]; \ \ \ \ /*\ create\ the\ pmemblk\ pool\ or\ open\ it\ if\ it\ already\ exists\ */ \ \ \ \ pbp\ =\ pmemblk_create(path,\ ELEMENT_SIZE,\ POOL_SIZE,\ 0666); \ \ \ \ if\ (pbp\ ==\ NULL) \ \ \ \ \ \ \ \ pbp\ =\ pmemblk_open(path,\ ELEMENT_SIZE); \ \ \ \ if\ (pbp\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror(path); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ how\ many\ elements\ fit\ into\ the\ file?\ */ \ \ \ \ nelements\ =\ pmemblk_nblock(pbp); \ \ \ \ printf("file\ holds\ %zu\ elements",\ nelements); \ \ \ \ /*\ store\ a\ block\ at\ index\ 5\ */ \ \ \ \ strcpy(buf,\ "hello,\ world"); \ \ \ \ if\ (pmemblk_write(pbp,\ buf,\ 5)\ <\ 0)\ { \ \ \ \ \ \ \ \ perror("pmemblk_write"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ read\ the\ block\ at\ index\ 10\ (reads\ as\ zeros\ initially)\ */ \ \ \ \ if\ (pmemblk_read(pbp,\ buf,\ 10)\ <\ 0)\ { \ \ \ \ \ \ \ \ perror("pmemblk_read"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ zero\ out\ the\ block\ at\ index\ 5\ */ \ \ \ \ if\ (pmemblk_set_zero(pbp,\ 5)\ <\ 0)\ { \ \ \ \ \ \ \ \ perror("pmemblk_set_zero"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ ...\ */ \ \ \ \ pmemblk_close(pbp); } \f[] .fi .PP See for more examples using the \f[B]libpmemblk\f[] API. .SH BUGS .PP Unlike \f[B]libpmemobj\f[](7), data replication is not supported in \f[B]libpmemblk\f[]. Thus, specifying replica sections in pool set files is not allowed. .SH ACKNOWLEDGEMENTS .PP \f[B]libpmemblk\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]msync\f[](2), \f[B]dlclose\f[](3), \f[B]pmemblk_bsize\f[](3), \f[B]pmemblk_create\f[](3), \f[B]pmemblk_read\f[](3), \f[B]pmemblk_set_zero\f[](3), \f[B]pmem_is_pmem\f[](3), \f[B]pmem_persist\f[](3), \f[B]strerror\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemcto\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/libpmemcto.7000066400000000000000000000360461331545616200174150ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBPMEMCTO" "7" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libpmemcto\f[] \[en] close\-to\-open persistence (EXPERIMENTAL) .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ ...\ \-lpmemcto\ \-lpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *pmemcto_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Managing library behavior: .IP .nf \f[C] void\ pmemcto_set_funcs( \ \ \ \ void\ *(*malloc_func)(size_t\ size), \ \ \ \ void\ (*free_func)(void\ *ptr), \ \ \ \ void\ *(*realloc_func)(void\ *ptr,\ size_t\ size), \ \ \ \ char\ *(*strdup_func)(const\ char\ *s), \ \ \ \ void\ (*print_func)(const\ char\ *s)); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *pmemcto_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libpmemcto\f[] functions can be found on the following manual pages: .PP \f[B]pmemcto_aligned_alloc\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]pmemcto_malloc_usable_size\f[](3), \f[B]pmemcto_open\f[](3), \f[B]pmemcto_set_root_pointer\f[](3), \f[B]pmemcto_stats_print\f[](3), \f[B]pmemcto_strdup\f[](3), \f[B]pmemcto_wcsdup\f[](3) .SH DESCRIPTION .PP \f[B]libpmemcto\f[] is a \f[I]persistent memory\f[] allocator with no overhead imposed by run\-time flushing or transactional updates: .IP \[bu] 2 It runs at traditional \f[B]volatile\f[] memory allocator speeds \- there is no flushing or consistency check at run\-time. .IP \[bu] 2 An overhead imposed only when program exits normally and have to flush the file. .IP \[bu] 2 The program flushes the pool contents when it exits, and then rebuilds the pool on the next run. .IP \[bu] 2 If the program crashes before flushing the file (or if flushing fails), the pool is in an inconsistent state causing subsequent pool opening to fail. .PP \f[B]libpmemcto\f[] provides common \f[I]malloc\-like\f[] interfaces to persistent memory pools built on memory\-mapped files. \f[B]libpmemcto\f[] uses the \f[B]mmap\f[](2) system call to create a pool of persistent memory. The library is intended for applications using \f[I]Direct Access\f[] storage (DAX), which is memory\-addressable persistent storage that supports load/store access without being paged via the system page cache. A Persistent Memory\-aware file system is typically used to provide this type of access. Memory\-mapping a file from a Persistent Memory\-aware file system provides the raw memory pools, and this library supplies the more familiar \f[I]malloc\-like\f[] interfaces on top of those pools. \f[B]libpmemcto\f[] is one of a collection of persistent memory libraries available, the others are: .IP \[bu] 2 \f[B]libpmemobj\f[](7), a general use persistent memory API, providing memory allocation and transactional operations on variable\-sized objects. .IP \[bu] 2 \f[B]libpmemblk\f[](7), providing pmem\-resident arrays of fixed\-sized blocks with atomic updates. .IP \[bu] 2 \f[B]libpmemlog\f[](7), providing a pmem\-resident log file. .IP \[bu] 2 \f[B]libpmem\f[](7), low\-level persistent memory support. .PP Under normal usage, \f[B]libpmemcto\f[] will never print messages or intentionally cause the process to exit. Exceptions to this are prints caused by calls to \f[B]pmemcto_stats_print\f[](3), or by enabling debugging as described under \f[B]DEBUGGING AND ERROR HANDLING\f[] below. The library uses \f[B]pthreads\f[](7) to be fully MT\-safe, but never creates or destroys threads itself. The library does not make use of any signals, networking, and never calls \f[B]select\f[]() or \f[B]poll\f[](). .PP The system memory allocation routines like \f[B]malloc\f[]() and \f[B]free\f[]() are used by \f[B]libpmemcto\f[] for managing a small amount of run\-time state, but applications are allowed to override these calls if necessary (see \f[B]pmemcto_set_funcs\f[]()). .PP This library builds on the low\-level pmem support provided by \f[B]libpmem\f[](7). .PP To use close\-to\-open persistence supplied by \f[B]libpmemcto\f[], a \f[I]memory pool\f[] is first created using the \f[B]pmemcto_create\f[]() function described in \f[B]pmemcto_open\f[](3). The other \f[B]libpmemcto\f[] functions operate on the resulting block memory pool using the opaque handle, of type \f[I]PMEMctopool*\f[], that is returned by \f[B]pmemcto_create\f[]() or \f[B]pmemcto_open\f[](). Internally, \f[B]libpmemcto\f[] will use either \f[B]pmem_persist\f[](3) or \f[B]msync\f[](2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the \f[B]pmem_is_pmem\f[](3) function in \f[B]libpmem\f[](7) for more information). There is no need for applications to flush changes directly when using the close\-to\-open persistence memory API provided by \f[B]libpmemcto\f[]. .SH CAVEATS .PP \f[B]libpmemcto\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]pmemcto_check_version\f[]() function is used to determine whether the installed \f[B]libpmemcto\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ pmemcto_check_version(PMEMCTO_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEMCTO_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP When the version check performed by \f[B]pmemcto_check_version\f[]() is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by \f[B]pmemcto_check_version\f[]() must not be modified or freed. .SH MANAGING LIBRARY BEHAVIOR .PP The \f[B]pmemcto_set_funcs\f[]() function allows an application to override memory allocation calls used internally by \f[B]libpmemcto\f[]. Passing in NULL for any of the handlers will cause the \f[B]libpmemcto\f[] default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4\-8 kilobytes for each memory pool in use. .SH DEBUGGING AND ERROR HANDLING .PP The \f[B]pmemcto_errormsg\f[]() function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code, as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libpmemcto\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libpmemcto\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lpmemcto\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. If an error is detected in a call to \f[B]libpmemcto\f[], the error message describing the failure may be retrieved with \f[B]pmemcto_errormsg\f[]() as described above. .PP A second version of \f[B]libpmemcto\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the \f[B]LD_LIBRARY_PATH\f[] environment variable to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]PMEMCTO_LOG_LEVEL\f[] .PP The value of \f[B]PMEMCTO_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]PMEMCTO_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. The same information may be retrieved using \f[B]pmemcto_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]libpmemcto\f[] developers. .PP Unless \f[B]PMEMCTO_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]PMEMCTO_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]PMEMCTO_LOG_FILE\f[] is not set, the logging output is written to \f[I]stderr\f[]. .PP See also \f[B]libpmem\f[](7) for information on other environment variables that may affect \f[B]libpmemcto\f[] behavior. .SH EXAMPLE .PP The following example creates a memory pool, allocates some memory to contain the string \[lq]hello, world\[rq], and then frees that memory. .IP .nf \f[C] #include\ #include\ #include\ #include\ #include\ #include\ #include\ /*\ size\ of\ the\ pmemcto\ pool\ \-\-\ 1\ GB\ */ #define\ POOL_SIZE\ ((size_t)(1\ <<\ 30)) /*\ name\ of\ our\ layout\ in\ the\ pool\ */ #define\ LAYOUT_NAME\ "example_layout" struct\ root\ { \ \ \ \ char\ *str; \ \ \ \ char\ *data; }; int main(int\ argc,\ char\ *argv[]) { \ \ \ \ const\ char\ path[]\ =\ "/pmem\-fs/myfile"; \ \ \ \ PMEMctopool\ *pcp; \ \ \ \ /*\ create\ the\ pmemcto\ pool\ or\ open\ it\ if\ already\ exists\ */ \ \ \ \ pcp\ =\ pmemcto_create(path,\ LAYOUT_NAME,\ POOL_SIZE,\ 0666); \ \ \ \ if\ (pcp\ ==\ NULL) \ \ \ \ \ \ \ \ pcp\ =\ pmemcto_open(path,\ LAYOUT_NAME); \ \ \ \ if\ (pcp\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror(path); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ get\ the\ root\ object\ pointer\ */ \ \ \ \ struct\ root\ *rootp\ =\ pmemcto_get_root_pointer(pcp); \ \ \ \ if\ (rootp\ ==\ NULL)\ { \ \ \ \ \ \ \ \ /*\ allocate\ root\ object\ */ \ \ \ \ \ \ \ \ rootp\ =\ pmemcto_malloc(pcp,\ sizeof(*rootp)); \ \ \ \ \ \ \ \ if\ (rootp\ ==\ NULL)\ { \ \ \ \ \ \ \ \ \ \ \ \ perror(pmemcto_errormsg()); \ \ \ \ \ \ \ \ \ \ \ \ exit(1); \ \ \ \ \ \ \ \ } \ \ \ \ \ \ \ \ /*\ save\ the\ root\ object\ pointer\ */ \ \ \ \ \ \ \ \ pmemcto_set_root_pointer(pcp,\ rootp); \ \ \ \ \ \ \ \ rootp\->str\ =\ pmemcto_strdup(pcp,\ "Hello\ World!"); \ \ \ \ \ \ \ \ rootp\->data\ =\ NULL; \ \ \ \ } \ \ \ \ /*\ ...\ */ \ \ \ \ pmemcto_close(pcp); } \f[] .fi .PP See for more examples using the \f[B]libpmemcto\f[] API. .SH BUGS .PP Unlike \f[B]libpmemobj\f[](3), data replication is not supported in \f[B]libpmemcto\f[]. Thus, it is not allowed to specify replica sections in pool set files. .SH NOTES .PP Unlike the normal \f[B]malloc\f[](), which asks the system for additional memory when it runs out, \f[B]libpmemcto\f[] allocates the size it is told to and never attempts to grow or shrink that memory pool. .SH AVAILABILITY .PP \f[B]libpmemcto\f[] is part of the PMDK since version 1.4 and is available from .SH ACKNOWLEDGEMENTS .PP \f[B]libpmemcto\f[] depends on jemalloc, written by Jason Evans, to do the heavy lifting of managing dynamic memory allocation. See: .PP \f[B]libpmemcto\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]ndctl\-create\-namespace\f[](1), \f[B]dlclose\f[](2), \f[B]mmap\f[](2), \f[B]jemalloc\f[](3), \f[B]malloc\f[](3), \f[B]pmemcto_aligned_alloc\f[](3), \f[B]pmemcto_errormsg\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]pmemcto_malloc_usable_size\f[](3), \f[B]pmemcto_open\f[](3), \f[B]pmemcto_set_root_pointer\f[](3), \f[B]pmemcto_stats_print\f[](3), \f[B]pmemcto_strdup\f[](3), \f[B]pmemcto_wcsdup\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/libpmemlog.7000066400000000000000000000320721331545616200174040ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBPMEMLOG" "7" "2018-05-21" "PMDK - pmemlog API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libpmemlog\f[] \[en] persistent memory resident log file .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ ...\ \-lpmemlog\ \-lpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *pmemlog_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Managing library behavior: .IP .nf \f[C] void\ pmemlog_set_funcs( \ \ \ \ void\ *(*malloc_func)(size_t\ size), \ \ \ \ void\ (*free_func)(void\ *ptr), \ \ \ \ void\ *(*realloc_func)(void\ *ptr,\ size_t\ size), \ \ \ \ char\ *(*strdup_func)(const\ char\ *s)); \f[] .fi .SS Error handling: .IP .nf \f[C] int\ pmemlog_check(const\ char\ *path); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libpmemlog\f[] functions can be found on the following manual pages: .PP \f[B]pmemlog_create\f[](3), \f[B]pmemlog_nbyte\f[](3), \f[B]pmemlog_append\f[](3), \f[B]pmemlog_tell\f[](3) .SH DESCRIPTION .PP \f[B]libpmemlog\f[] provides a log file in \f[I]persistent memory\f[] (pmem) such that additions to the log are appended atomically. This library is intended for applications using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of \f[I]non\-volatile memory DIMMs\f[] (NVDIMMs) provide this type of byte addressable access to storage. A \f[I]persistent memory aware file system\f[] is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in the load/store, non\-paged access to pmem. \f[B]libpmemlog\f[] builds on thistype of memory mapped file. .PP This library is for applications that need a persistent log file updated atomically (the updates cannot be \f[I]torn\f[] by program interruption such as power failures). This library builds on the low\-level pmem support provided by \f[B]libpmem\f[](7), handling the transactional update of the log, flushing to persistence, and recovery for the application. .PP \f[B]libpmemlog\f[] is one of a collection of persistent memory libraries available. The others are: .IP \[bu] 2 \f[B]libpmemobj\f[](7), a general use persistent memory API, providing memory allocation and transactional operations on variable\-sized objects. .IP \[bu] 2 \f[B]libpmemblk\f[](7), providing pmem\-resident arrays of fixed\-sized blocks with atomic updates. .IP \[bu] 2 \f[B]libpmemcto\f[](7), providing close\-to\-open persistence. .IP \[bu] 2 \f[B]libpmem\f[](7), low\-level persistent memory support. .PP Under normal usage, \f[B]libpmemlog\f[] will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under \f[B]DEBUGGING AND ERROR HANDLING\f[] below. .PP To use the pmem\-resident log file provided by \f[B]libpmemlog\f[], a \f[I]memory pool\f[] is first created. This is done with the \f[B]pmemlog_create\f[](3) function. The other functions mentioned above in SYNOPSIS section then operate on the resulting log memory pool. .PP Once created, the memory pool is represented by an opaque handle, of type \f[I]PMEMlogpool*\f[], which is passed to most of the other functions from \f[B]libpmemlog\f[]. Internally, \f[B]libpmemlog\f[] will use either \f[B]pmem_persist\f[](3) or \f[B]msync\f[](2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the \f[B]pmem_is_pmem\f[](3) function in \f[B]libpmem\f[](7) for more information). There is no need for applications to flush changes directly when using the log memory API provided by \f[B]libpmemlog\f[]. .SH CAVEATS .PP \f[B]libpmemlog\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]pmemlog_check_version\f[]() function is used to determine whether the installed \f[B]libpmemlog\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information provided by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ pmemlog_check_version(PMEMLOG_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEMLOG_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP On success, \f[B]pmemlog_check_version\f[]() returns NULL. Otherwise, the return value is a static string describing the reason the version check failed. The string returned by \f[B]pmemlog_check_version\f[]() must not be modified or freed. .SH MANAGING LIBRARY BEHAVIOR .PP The \f[B]pmemlog_set_funcs\f[]() function allows an application to override memory allocation calls used internally by \f[B]libpmemlog\f[]. Passing in NULL for any of the handlers will cause the \f[B]libpmemlog\f[] default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4\-8 kilobytes for each memory pool in use. .SH DEBUGGING AND ERROR HANDLING .PP The \f[B]pmemlog_errormsg\f[]() function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libpmemlog\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libpmemlog\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lpmemlog\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. .PP A second version of \f[B]libpmemlog\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the environment variable \f[B]LD_LIBRARY_PATH\f[] to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]PMEMLOG_LOG_LEVEL\f[] .PP The value of \f[B]PMEMLOG_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]PMEMLOG_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. The same information may be retrieved using \f[B]pmemlog_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]libpmemlog\f[] developers. .PP Unless \f[B]PMEMLOG_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]PMEMLOG_LOG_FILE\f[] .PP Specifies the name of a file name where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]PMEMLOG_LOG_FILE\f[] is not set, logging output is written to \f[I]stderr\f[]. .PP See also \f[B]libpmem\f[](7) for information about other environment variables affecting \f[B]libpmemlog\f[] behavior. .SH EXAMPLE .PP The following example illustrates how the \f[B]libpmemlog\f[] API is used. .IP .nf \f[C] #include\ #include\ #include\ #include\ #include\ #include\ #include\ /*\ size\ of\ the\ pmemlog\ pool\ \-\-\ 1\ GB\ */ #define\ POOL_SIZE\ ((size_t)(1\ <<\ 30)) /* \ *\ printit\ \-\-\ log\ processing\ callback\ for\ use\ with\ pmemlog_walk() \ */ int printit(const\ void\ *buf,\ size_t\ len,\ void\ *arg) { \ \ \ \ fwrite(buf,\ len,\ 1,\ stdout); \ \ \ \ return\ 0; } int main(int\ argc,\ char\ *argv[]) { \ \ \ \ const\ char\ path[]\ =\ "/pmem\-fs/myfile"; \ \ \ \ PMEMlogpool\ *plp; \ \ \ \ size_t\ nbyte; \ \ \ \ char\ *str; \ \ \ \ /*\ create\ the\ pmemlog\ pool\ or\ open\ it\ if\ it\ already\ exists\ */ \ \ \ \ plp\ =\ pmemlog_create(path,\ POOL_SIZE,\ 0666); \ \ \ \ if\ (plp\ ==\ NULL) \ \ \ \ \ \ \ \ plp\ =\ pmemlog_open(path); \ \ \ \ if\ (plp\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror(path); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ how\ many\ bytes\ does\ the\ log\ hold?\ */ \ \ \ \ nbyte\ =\ pmemlog_nbyte(plp); \ \ \ \ printf("log\ holds\ %zu\ bytes",\ nbyte); \ \ \ \ /*\ append\ to\ the\ log...\ */ \ \ \ \ str\ =\ "This\ is\ the\ first\ string\ appended"; \ \ \ \ if\ (pmemlog_append(plp,\ str,\ strlen(str))\ <\ 0)\ { \ \ \ \ \ \ \ \ perror("pmemlog_append"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ str\ =\ "This\ is\ the\ second\ string\ appended"; \ \ \ \ if\ (pmemlog_append(plp,\ str,\ strlen(str))\ <\ 0)\ { \ \ \ \ \ \ \ \ perror("pmemlog_append"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ /*\ print\ the\ log\ contents\ */ \ \ \ \ printf("log\ contains:"); \ \ \ \ pmemlog_walk(plp,\ 0,\ printit,\ NULL); \ \ \ \ pmemlog_close(plp); } \f[] .fi .PP See for more examples using the \f[B]libpmemlog\f[] API. .SH BUGS .PP Unlike \f[B]libpmemobj\f[](7), data replication is not supported in \f[B]libpmemlog\f[]. Thus, specifying replica sections in pool set files is not allowed. .SH ACKNOWLEDGEMENTS .PP \f[B]libpmemlog\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]msync\f[](2), \f[B]pmemlog_append\f[](3), \f[B]pmemlog_create\f[](3), \f[B]pmemlog_nbyte\f[](3), \f[B]pmemlog_tell\f[](3), \f[B]strerror\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemblk\f[](7), \f[B]libpmemcto\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/libpmemobj.7000066400000000000000000000267001331545616200173760ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBPMEMOBJ" "7" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libpmemobj\f[] \[en] persistent memory transactional object store .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ \-std=gnu99\ ...\ \-lpmemobj\ \-lpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *pmemobj_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Managing library behavior: .IP .nf \f[C] void\ pmemobj_set_funcs( \ \ \ \ void\ *(*malloc_func)(size_t\ size), \ \ \ \ void\ (*free_func)(void\ *ptr), \ \ \ \ void\ *(*realloc_func)(void\ *ptr,\ size_t\ size), \ \ \ \ char\ *(*strdup_func)(const\ char\ *s)); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *pmemobj_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libpmemobj\f[] functions can be found on the following manual pages: .IP \[bu] 2 create, open, close and validate: \f[B]pmemobj_open\f[](3) .IP \[bu] 2 low\-level memory manipulation: \f[B]pmemobj_memcpy_persist\f[](3) .IP \[bu] 2 locking: \f[B]pmemobj_mutex_zero\f[](3) .IP \[bu] 2 persistent object identifier: \f[B]OID_IS_NULL\f[](3) .IP \[bu] 2 type\-safety: \f[B]TOID_DECLARE\f[](3) .IP \[bu] 2 layout declaration: \f[B]POBJ_LAYOUT_BEGIN\f[](3) .IP \[bu] 2 non\-transactional atomic allocations: \f[B]pmemobj_alloc\f[](3) .IP \[bu] 2 root object management: \f[B]pmemobj_root\f[](3) .IP \[bu] 2 object containers: \f[B]pmemobj_first\f[](3) .IP \[bu] 2 non\-transactional persistent atomic circular doubly\-linked list: \f[B]pmemobj_list_insert\f[](3), \f[B]POBJ_LIST_HEAD\f[](3) .IP \[bu] 2 transactional object manipulation: \f[B]pmemobj_tx_begin\f[](3), \f[B]pmemobj_tx_add_range\f[](3), \f[B]pmemobj_tx_alloc\f[](3) .IP \[bu] 2 control and statistics: \f[B]pmemobj_ctl_get\f[](3) .IP \[bu] 2 delayed atomicity actions: \f[B]pmemobj_action\f[](3) (EXPERIMENTAL) .SH DESCRIPTION .PP \f[B]libpmemobj\f[] provides a transactional object store in \f[I]persistent memory\f[] (pmem) for applications that require transactions and persistent memory management using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of \f[I]non\-volatile memory DIMMs\f[] (NVDIMMs) provide this type of byte addressable access to storage. A \f[I]persistent memory aware file system\f[] is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in load/store, non\-paged access to pmem. \f[B]libpmemobj\f[] builds on this type of memory mapped file using the low\-level pmem support provided by \f[B]libpmem\f[](7), handling the transactional updates, flushing changes to persistence, and managing recovery for the application. .PP \f[B]libpmemobj\f[] requires the \f[B]\-std=gnu99\f[] compilation flag to build properly. .PP \f[B]libpmemobj\f[] is one of a collection of persistent memory libraries available. The others are: .IP \[bu] 2 \f[B]libpmemblk\f[](7), providing pmem\-resident arrays of fixed\-sized blocks with atomic updates. .IP \[bu] 2 \f[B]libpmemlog\f[](7), providing a pmem\-resident log file. .IP \[bu] 2 \f[B]libpmemcto\f[](7), providing close\-to\-open persistence. .IP \[bu] 2 \f[B]libpmem\f[](7), low\-level persistent memory support. .PP Under normal usage, \f[B]libpmemobj\f[] will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under \f[B]DEBUGGING AND ERROR HANDLING\f[], below. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]pmemobj_check_version\f[]() function is used to see if the installed \f[B]libpmemobj\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ pmemobj_check_version(PMEMOBJ_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEMOBJ_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP On success, \f[B]pmemobj_check_version\f[]() returns NULL. Otherwise, the return value is a static string describing the reason the version check failed. The string returned by \f[B]pmemobj_check_version\f[]() must not be modified or freed. .SH MANAGING LIBRARY BEHAVIOR .PP The \f[B]pmemobj_set_funcs\f[]() function allows an application to override memory allocation calls used internally by \f[B]libpmemobj\f[]. Passing in NULL for any of the handlers will cause the \f[B]libpmemobj\f[] default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4\-8 kilobytes for each memory pool in use. .PP By default, \f[B]libpmemobj\f[] supports up to 1024 parallel transactions/allocations. For debugging purposes it is possible to decrease this value by setting the \f[B]PMEMOBJ_NLANES\f[] environment variable to the desired limit. .SH DEBUGGING AND ERROR HANDLING .PP If an error is detected during the call to a \f[B]libpmemobj\f[] function, the application may retrieve an error message describing the reason for the failure from \f[B]pmemobj_errormsg\f[](). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libpmemobj\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libpmemobj\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lpmemobj\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. .PP A second version of \f[B]libpmemobj\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the environment variable \f[B]LD_LIBRARY_PATH\f[] to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]PMEMOBJ_LOG_LEVEL\f[] .PP The value of \f[B]PMEMOBJ_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]PMEMOBJ_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. The same information may be retrieved using \f[B]pmemobj_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]libpmemobj\f[] developers. .PP Unless \f[B]PMEMOBJ_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]PMEMOBJ_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]PMEMOBJ_LOG_FILE\f[] is not set, logging output is written to \f[I]stderr\f[]. .PP See also \f[B]libpmem\f[](7) to get information about other environment variables affecting \f[B]libpmemobj\f[] behavior. .SH EXAMPLE .PP See for examples using the \f[B]libpmemobj\f[] API. .SH ACKNOWLEDGEMENTS .PP \f[B]libpmemobj\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]OID_IS_NULL\f[](3), \f[B]pmemobj_alloc\f[](3), \f[B]pmemobj_ctl_get\f[](3), \f[B]pmemobj_ctl_set\f[](3), \f[B]pmemobj_first\f[](3), \f[B]pmemobj_list_insert\f[](3), \f[B]pmemobj_memcpy_persist\f[](3), \f[B]pmemobj_mutex_zero\f[](3), \f[B]pmemobj_open\f[](3), \f[B]pmemobj_root\f[](3), \f[B]pmemobj_tx_add_range\f[](3), \f[B]pmemobj_tx_alloc\f[](3), \f[B]pmemobj_tx_begin\f[](3), \f[B]POBJ_LAYOUT_BEGIN\f[](3), \f[B]POBJ_LIST_HEAD\f[](3), \f[B]strerror\f[](3), \f[B]TOID_DECLARE\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemblk\f[](7), \f[B]libpmemcto\f[](7), \f[B]libpmemlog\f[](7), \f[B]libvmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/libpmempool.7000066400000000000000000000262311331545616200175740ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBPMEMPOOL" "7" "2018-05-21" "PMDK - pmempool API version 1.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libpmempool\f[] \[en] persistent memory pool management library .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ \-std=gnu99\ ...\ \-lpmempool\ \-lpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *pmempool_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *pmempool_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libpmempool\f[] functions can be found on the following manual pages: .IP \[bu] 2 health check functions: \f[B]pmempool_check_init\f[](3) .IP \[bu] 2 pool set synchronization and transformation: \f[B]pmempool_sync\f[](3) .IP \[bu] 2 pool set management functions: \f[B]pmempool_rm\f[](3) .SH DESCRIPTION .PP \f[B]libpmempool\f[] provides a set of utilities for off\-line analysis and manipulation of a \f[I]pool\f[]. A \f[I]pool\f[] in this manpage means a pmemobj pool, pmemblk pool, pmemlog pool or BTT layout, independent of the underlying storage. Some \f[B]libpmempool\f[] functions are required to work without any impact on the \f[I]pool\f[] but some may create a new or modify an existing \f[I]pool\f[]. .PP \f[B]libpmempool\f[] is for applications that need high reliability or built\-in troubleshooting. It may be useful for testing and debugging purposes also. .PP \f[B]libpmempool\f[] introduces functionality of pool set health check, synchronization, transformation and removal. .SH CAVEATS .PP \f[B]libpmempool\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .PP \f[B]libpmempool\f[] requires the \f[B]\-std=gnu99\f[] compilation flag to build properly. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]pmempool_check_version\f[]() function is used to see if the installed \f[B]libpmempool\f[] supports the version of the library API required by an application. The easiest way to do this for the application is to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ pmempool_check_version(PMEMPOOL_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEMPOOL_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP When the version check performed by \f[B]pmempool_check_version\f[]() is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by \f[B]pmempool_check_version\f[]() must not be modified or freed. .SH DEBUGGING AND ERROR HANDLING .PP If an error is detected during the call to a \f[B]libpmempool\f[] function, the application may retrieve an error message describing the reason for the failure from \f[B]pmempool_errormsg\f[](). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libpmempool\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libpmempool\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lpmempool\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. .PP A second version of \f[B]libpmempool\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the environment variable \f[B]LD_LIBRARY_PATH\f[] to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]PMEMPOOL_LOG_LEVEL\f[] .PP The value of \f[B]PMEMPOOL_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]PMEMPOOL_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged (in addition to returning the \f[I]errno\f[]\-based errors as usual). The same information may be retrieved using \f[B]pmempool_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]libpmempool\f[] developers. .PP Unless \f[B]PMEMPOOL_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]PMEMPOOL_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]PMEMPOOL_LOG_FILE\f[] is not set, output is written to \f[I]stderr\f[]. .SH EXAMPLE .PP The following example illustrates how the \f[B]libpmempool\f[] API is used. The program detects the type and checks consistency of given pool. If there are any issues detected, the pool is automatically repaired. .IP .nf \f[C] #include\ #include\ #include\ #include\ #include\ #define\ PATH\ "./pmem\-fs/myfile" #define\ CHECK_FLAGS\ (PMEMPOOL_CHECK_FORMAT_STR|PMEMPOOL_CHECK_REPAIR|\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PMEMPOOL_CHECK_VERBOSE) int main(int\ argc,\ char\ *argv[]) { \ \ \ \ PMEMpoolcheck\ *ppc; \ \ \ \ struct\ pmempool_check_status\ *status; \ \ \ \ enum\ pmempool_check_result\ ret; \ \ \ \ /*\ arguments\ for\ check\ */ \ \ \ \ struct\ pmempool_check_args\ args\ =\ { \ \ \ \ \ \ \ \ .path\ \ \ \ \ \ \ =\ PATH, \ \ \ \ \ \ \ \ .backup_path\ \ \ \ =\ NULL, \ \ \ \ \ \ \ \ .pool_type\ \ =\ PMEMPOOL_POOL_TYPE_DETECT, \ \ \ \ \ \ \ \ .flags\ \ \ \ \ \ =\ CHECK_FLAGS \ \ \ \ }; \ \ \ \ /*\ initialize\ check\ context\ */ \ \ \ \ if\ ((ppc\ =\ pmempool_check_init(&args,\ sizeof(args)))\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror("pmempool_check_init"); \ \ \ \ \ \ \ \ exit(EXIT_FAILURE); \ \ \ \ } \ \ \ \ /*\ perform\ check\ and\ repair,\ answer\ \[aq]yes\[aq]\ for\ each\ question\ */ \ \ \ \ while\ ((status\ =\ pmempool_check(ppc))\ !=\ NULL)\ { \ \ \ \ \ \ \ \ switch\ (status\->type)\ { \ \ \ \ \ \ \ \ case\ PMEMPOOL_CHECK_MSG_TYPE_ERROR: \ \ \ \ \ \ \ \ \ \ \ \ printf("%s\\n",\ status\->str.msg); \ \ \ \ \ \ \ \ \ \ \ \ break; \ \ \ \ \ \ \ \ case\ PMEMPOOL_CHECK_MSG_TYPE_INFO: \ \ \ \ \ \ \ \ \ \ \ \ printf("%s\\n",\ status\->str.msg); \ \ \ \ \ \ \ \ \ \ \ \ break; \ \ \ \ \ \ \ \ case\ PMEMPOOL_CHECK_MSG_TYPE_QUESTION: \ \ \ \ \ \ \ \ \ \ \ \ printf("%s\\n",\ status\->str.msg); \ \ \ \ \ \ \ \ \ \ \ \ status\->str.answer\ =\ "yes"; \ \ \ \ \ \ \ \ \ \ \ \ break; \ \ \ \ \ \ \ \ default: \ \ \ \ \ \ \ \ \ \ \ \ pmempool_check_end(ppc); \ \ \ \ \ \ \ \ \ \ \ \ exit(EXIT_FAILURE); \ \ \ \ \ \ \ \ } \ \ \ \ } \ \ \ \ /*\ finalize\ the\ check\ and\ get\ the\ result\ */ \ \ \ \ ret\ =\ pmempool_check_end(ppc); \ \ \ \ switch\ (ret)\ { \ \ \ \ \ \ \ \ case\ PMEMPOOL_CHECK_RESULT_CONSISTENT: \ \ \ \ \ \ \ \ case\ PMEMPOOL_CHECK_RESULT_REPAIRED: \ \ \ \ \ \ \ \ \ \ \ \ return\ 0; \ \ \ \ \ \ \ \ default: \ \ \ \ \ \ \ \ \ \ \ \ return\ 1; \ \ \ \ } } \f[] .fi .PP See for more examples using the \f[B]libpmempool\f[] API. .SH ACKNOWLEDGEMENTS .PP \f[B]libpmempool\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]dlclose\f[](3), \f[B]pmempool_check_init\f[](3), \f[B]pmempool_rm\f[](3), \f[B]pmempool_sync\f[](3), \f[B]strerror\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemblk\f[](7), \f[B]libpmemcto\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/librpmem.7000066400000000000000000000412351331545616200170650ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBRPMEM" "7" "2018-05-21" "PMDK - rpmem API version 1.2" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]librpmem\f[] \[en] remote persistent memory support library (EXPERIMENTAL) .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ ...\ \-lrpmem \f[] .fi .SS Library API versioning: .IP .nf \f[C] const\ char\ *rpmem_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *rpmem_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]librpmem\f[] functions can be found on the following manual pages: .IP \[bu] 2 \f[B]rpmem_create\f[](3), \f[B]rpmem_persist\f[](3) .SH DESCRIPTION .PP \f[B]librpmem\f[] provides low\-level support for remote access to \f[I]persistent memory\f[] (pmem) utilizing RDMA\-capable RNICs. The library can be used to remotely replicate a memory region over the RDMA protocol. It utilizes an appropriate persistency mechanism based on the remote node's platform capabilities. \f[B]librpmem\f[] utilizes the \f[B]ssh\f[](1) client to authenticate a user on the remote node, and for encryption of the connection's out\-of\-band configuration data. See \f[B]SSH\f[], below, for details. .PP The maximum replicated memory region size can not be bigger than the maximum locked\-in\-memory address space limit. See \f[B]memlock\f[] in \f[B]limits.conf\f[](5) for more details. .PP This library is for applications that use remote persistent memory directly, without the help of any library\-supplied transactions or memory allocation. Higher\-level libraries that build on \f[B]libpmem\f[](7) are available and are recommended for most applications, see: .IP \[bu] 2 \f[B]libpmemobj\f[](7), a general use persistent memory API, providing memory allocation and transactional operations on variable\-sized objects. .SH TARGET NODE ADDRESS FORMAT .IP .nf \f[C] [\@][:] \f[] .fi .PP The target node address is described by the \f[I]hostname\f[] which the client connects to, with an optional \f[I]user\f[] name. The user must be authorized to authenticate to the remote machine without querying for password/passphrase. The optional \f[I]port\f[] number is used to establish the SSH connection. The default port number is 22. .SH REMOTE POOL ATTRIBUTES .PP The \f[I]rpmem_pool_attr\f[] structure describes a remote pool and is stored in remote pool's metadata. This structure must be passed to the \f[B]rpmem_create\f[](3) function by caller when creating a pool on remote node. When opening the pool using \f[B]rpmem_open\f[](3) function the appropriate fields are read from pool's metadata and returned back to the caller. .IP .nf \f[C] #define\ RPMEM_POOL_HDR_SIG_LEN\ \ \ \ 8 #define\ RPMEM_POOL_HDR_UUID_LEN\ \ \ 16 #define\ RPMEM_POOL_USER_FLAGS_LEN\ 16 struct\ rpmem_pool_attr\ { \ \ \ \ char\ signature[RPMEM_POOL_HDR_SIG_LEN]; \ \ \ \ uint32_t\ major; \ \ \ \ uint32_t\ compat_features; \ \ \ \ uint32_t\ incompat_features; \ \ \ \ uint32_t\ ro_compat_features; \ \ \ \ unsigned\ char\ poolset_uuid[RPMEM_POOL_HDR_UUID_LEN]; \ \ \ \ unsigned\ char\ uuid[RPMEM_POOL_HDR_UUID_LEN]; \ \ \ \ unsigned\ char\ next_uuid[RPMEM_POOL_HDR_UUID_LEN]; \ \ \ \ unsigned\ char\ prev_uuid[RPMEM_POOL_HDR_UUID_LEN]; \ \ \ \ unsigned\ char\ user_flags[RPMEM_POOL_USER_FLAGS_LEN]; }; \f[] .fi .PP The \f[I]signature\f[] field is an 8\-byte field which describes the pool's on\-media format. .PP The \f[I]major\f[] field is a major version number of the pool's on\-media format. .PP The \f[I]compat_features\f[] field is a mask describing compatibility of pool's on\-media format optional features. .PP The \f[I]incompat_features\f[] field is a mask describing compatibility of pool's on\-media format required features. .PP The \f[I]ro_compat_features\f[] field is a mask describing compatibility of pool's on\-media format features. If these features are not available, the pool shall be opened in read\-only mode. .PP The \f[I]poolset_uuid\f[] field is an UUID of the pool which the remote pool is associated with. .PP The \f[I]uuid\f[] field is an UUID of a first part of the remote pool. This field can be used to connect the remote pool with other pools in a list. .PP The \f[I]next_uuid\f[] and \f[I]prev_uuid\f[] fields are UUIDs of next and previous replicas respectively. These fields can be used to connect the remote pool with other pools in a list. .PP The \f[I]user_flags\f[] field is a 16\-byte user\-defined flags. .SH SSH .PP \f[B]librpmem\f[] utilizes the \f[B]ssh\f[](1) client to login and execute the \f[B]rpmemd\f[](1) process on the remote node. By default, \f[B]ssh\f[](1) is executed with the \f[B]\-4\f[] option, which forces using \f[B]IPv4\f[] addressing. .PP For debugging purposes, both the ssh client and the commands executed on the remote node may be overridden by setting the \f[B]RPMEM_SSH\f[] and \f[B]RPMEM_CMD\f[] environment variables, respectively. See \f[B]ENVIRONMENT\f[] for details. .SH FORK .PP The \f[B]ssh\f[](1) client is executed by \f[B]rpmem_open\f[](3) and \f[B]rpmem_create\f[](3) after forking a child process using \f[B]fork\f[](2). The application must take this into account when using \f[B]wait\f[](2) and \f[B]waitpid\f[](2), which may return the \f[I]PID\f[] of the \f[B]ssh\f[](1) process executed by \f[B]librpmem\f[]. .PP If \f[B]fork\f[](2) support is not enabled in \f[B]libibverbs\f[], \f[B]rpmem_open\f[](3) and \f[B]rpmem_create\f[](3) will fail. By default, \f[B]fabric\f[](7) initializes \f[B]libibverbs\f[] with \f[B]fork\f[](2) support by calling the \f[B]ibv_fork_init\f[](3) function. See \f[B]fi_verbs\f[](7) for more details. .SH CAVEATS .PP \f[B]librpmem\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .PP \f[B]librpmem\f[] registers a pool as a single memory region. A Chelsio T4 and T5 hardware can not handle a memory region greater than or equal to 8GB due to a hardware bug. So \f[I]pool_size\f[] value for \f[B]rpmem_create\f[](3) and \f[B]rpmem_open\f[](3) using this hardware can not be greater than or equal to 8GB. .SH LIBRARY API VERSIONING .PP This section describes how the library API is versioned, allowing applications to work with an evolving API. .PP The \f[B]rpmem_check_version\f[]() function is used to see if the installed \f[B]librpmem\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ rpmem_check_version(RPMEM_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ RPMEM_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP When the version check performed by \f[B]rpmem_check_version\f[]() is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by \f[B]rpmem_check_version\f[]() must not be modified or freed. .SH ENVIRONMENT .PP \f[B]librpmem\f[] can change its default behavior based on the following environment variables. These are largely intended for testing and are not normally required. .IP \[bu] 2 \f[B]RPMEM_SSH\f[]=\f[I]ssh_client\f[] .PP Setting this environment variable overrides the default \f[B]ssh\f[](1) client command name. .IP \[bu] 2 \f[B]RPMEM_CMD\f[]=\f[I]cmd\f[] .PP Setting this environment variable overrides the default command executed on the remote node using either \f[B]ssh\f[](1) or the alternative remote shell command specified by \f[B]RPMEM_SSH\f[]. .PP \f[B]RPMEM_CMD\f[] can contain multiple commands separated by a vertical bar (\f[C]|\f[]). Each consecutive command is executed on the remote node in order read from a pool set file. This environment variable is read when the library is initialized, so \f[B]RPMEM_CMD\f[] must be set prior to application launch (or prior to \f[B]dlopen\f[](3) if \f[B]librpmem\f[] is being dynamically loaded). .IP \[bu] 2 \f[B]RPMEM_ENABLE_SOCKETS\f[]=0|1 .PP Setting this variable to 1 enables using \f[B]fi_sockets\f[](7) provider for in\-band RDMA connection. The \f[I]sockets\f[] provider does not support IPv6. It is required to disable IPv6 system wide if \f[B]RPMEM_ENABLE_SOCKETS\f[] == 1 and \f[I]target\f[] == localhost (or any other loopback interface address) and \f[B]SSH_CONNECTION\f[] variable (see \f[B]ssh\f[](1) for more details) contains IPv6 address after ssh to loopback interface. By default the \f[I]sockets\f[] provider is disabled. .IP \[bu] 2 \f[B]RPMEM_ENABLE_VERBS\f[]=0|1 .PP Setting this variable to 0 disables using \f[B]fi_verbs\f[](7) provider for in\-band RDMA connection. The \f[I]verbs\f[] provider is enabled by default. .IP \[bu] 2 \f[B]RPMEM_MAX_NLANES\f[]=\f[I]num\f[] .PP Limit the maximum number of lanes to \f[I]num\f[]. See \f[B]LANES\f[], in \f[B]rpmem_create\f[](3), for details. .SH DEBUGGING AND ERROR HANDLING .PP If an error is detected during the call to a \f[B]librpmem\f[] function, the application may retrieve an error message describing the reason for the failure from \f[B]rpmem_errormsg\f[](). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]librpmem\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]librpmem\f[] are typically available on a development system. The normal version, accessed when a program is linked using the \f[B]\-lrpmem\f[] option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. .PP A second version of \f[B]librpmem\f[], accessed when a program uses the libraries under \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the environment variable \f[B]LD_LIBRARY_PATH\f[] to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]RPMEM_LOG_LEVEL\f[] .PP The value of \f[B]RPMEM_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- This is the default level when \f[B]RPMEM_LOG_LEVEL\f[] is not set. No log messages are emitted at this level. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged (in addition to returning the \f[I]errno\f[]\-based errors as usual). The same information may be retrieved using \f[B]rpmem_errormsg\f[](). .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous and fairly obscure tracing information that is likely only useful to the \f[B]librpmem\f[] developers. .PP Unless \f[B]RPMEM_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]RPMEM_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]RPMEM_LOG_FILE\f[] is not set, logging output is written to \f[I]stderr\f[]. .SH EXAMPLE .PP The following example uses \f[B]librpmem\f[] to create a remote pool on given target node identified by given pool set name. The associated local memory pool is zeroed and the data is made persistent on remote node. Upon success the remote pool is closed. .IP .nf \f[C] #include\ #include\ #include\ #define\ POOL_SIZE\ \ \ \ (32\ *\ 1024\ *\ 1024) #define\ NLANES\ \ \ \ \ \ \ \ 4 unsigned\ char\ pool[POOL_SIZE]; int main(int\ argc,\ char\ *argv[]) { \ \ \ \ int\ ret; \ \ \ \ unsigned\ nlanes\ =\ NLANES; \ \ \ \ /*\ fill\ pool_attributes\ */ \ \ \ \ struct\ rpmem_pool_attr\ pool_attr; \ \ \ \ memset(&pool_attr,\ 0,\ sizeof(pool_attr)); \ \ \ \ /*\ create\ a\ remote\ pool\ */ \ \ \ \ RPMEMpool\ *rpp\ =\ rpmem_create("localhost",\ "pool.set", \ \ \ \ \ \ \ \ \ \ \ \ pool,\ POOL_SIZE,\ &nlanes,\ &pool_attr); \ \ \ \ if\ (!rpp)\ { \ \ \ \ \ \ \ \ fprintf(stderr,\ "rpmem_create:\ %s\\n",\ rpmem_errormsg()); \ \ \ \ \ \ \ \ return\ 1; \ \ \ \ } \ \ \ \ /*\ store\ data\ on\ local\ pool\ */ \ \ \ \ memset(pool,\ 0,\ POOL_SIZE); \ \ \ \ /*\ make\ local\ data\ persistent\ on\ remote\ node\ */ \ \ \ \ ret\ =\ rpmem_persist(rpp,\ 0,\ POOL_SIZE,\ 0); \ \ \ \ if\ (ret)\ { \ \ \ \ \ \ \ \ fprintf(stderr,\ "rpmem_persist:\ %s\\n",\ rpmem_errormsg()); \ \ \ \ \ \ \ \ return\ 1; \ \ \ \ } \ \ \ \ /*\ close\ the\ remote\ pool\ */ \ \ \ \ ret\ =\ rpmem_close(rpp); \ \ \ \ if\ (ret)\ { \ \ \ \ \ \ \ \ fprintf(stderr,\ "rpmem_close:\ %s\\n",\ rpmem_errormsg()); \ \ \ \ \ \ \ \ return\ 1; \ \ \ \ } \ \ \ \ return\ 0; } \f[] .fi .SH NOTE .PP The \f[B]librpmem\f[] API is experimental and may be subject to change in the future. However, using the remote replication in \f[B]libpmemobj\f[](7) is safe and backward compatibility will be preserved. .SH ACKNOWLEDGEMENTS .PP \f[B]librpmem\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]rpmemd\f[](1), \f[B]ssh\f[](1), \f[B]fork\f[](2), \f[B]dlclose\f[](3), \f[B]dlopen\f[](3), \f[B]ibv_fork_init\f[](3), \f[B]rpmem_create\f[](3), \f[B]rpmem_open\f[](3), \f[B]rpmem_persist\f[](3), \f[B]strerror\f[](3), \f[B]limits.conf\f[](5), \f[B]fabric\f[](7), \f[B]fi_sockets\f[](7), \f[B]fi_verbs\f[](7), \f[B]libpmem\f[](7), \f[B]libpmemblk\f[](7), \f[B]libpmemcto\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/libvmem.7000066400000000000000000000301701331545616200167050ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBVMEM" "7" "2018-05-21" "PMDK - vmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libvmem\f[] \[en] volatile memory allocation library .SH SYNOPSIS .IP .nf \f[C] #include\ cc\ ...\ \-lvmem \f[] .fi .SS Managing overall library behavior: .IP .nf \f[C] const\ char\ *vmem_check_version( \ \ \ \ unsigned\ major_required, \ \ \ \ unsigned\ minor_required); void\ vmem_set_funcs( \ \ \ \ void\ *(*malloc_func)(size_t\ size), \ \ \ \ void\ (*free_func)(void\ *ptr), \ \ \ \ void\ *(*realloc_func)(void\ *ptr,\ size_t\ size), \ \ \ \ char\ *(*strdup_func)(const\ char\ *s), \ \ \ \ void\ (*print_func)(const\ char\ *s)); \f[] .fi .SS Error handling: .IP .nf \f[C] const\ char\ *vmem_errormsg(void); \f[] .fi .SS Other library functions: .PP A description of other \f[B]libvmem\f[] functions can be found on the following manual pages: .IP \[bu] 2 memory pool management: \f[B]vmem_create\f[](3) .IP \[bu] 2 memory allocation related functions: \f[B]vmem_malloc\f[](3) .SH DESCRIPTION .PP \f[B]libvmem\f[] provides common \f[I]malloc\f[]\-like interfaces to memory pools built on memory\-mapped files. These interfaces are for traditional \f[B]volatile\f[] memory allocation but, unlike the functions described in \f[B]malloc\f[](3), the memory managed by \f[B]libvmem\f[] may have different attributes, depending on the file system containing the memory\-mapped files. In particular, \f[B]libvmem\f[] is part of the \f[I]Persistent Memory Development Kit\f[] because it is sometimes useful to use non\-volatile memory as a volatile memory pool, leveraging its capacity, cost, or performance characteristics. .PP \f[B]libvmem\f[] uses the \f[B]mmap\f[](2) system call to create a pool of volatile memory. The library is most useful when used with \f[I]Direct Access\f[] storage (DAX), which is memory\-addressable persistent storage that supports load/store access without being paged via the system page cache. A Persistent Memory\-aware file system is typically used to provide this type of access. Memory\-mapping a file from a Persistent Memory\-aware file system provides the raw memory pools, and this library supplies the more familiar \f[I]malloc\f[]\-like interfaces on top of those pools. .PP Under normal usage, \f[B]libvmem\f[] will never print messages or intentionally cause the process to exit. Exceptions to this are prints caused by calls to \f[B]vmem_stats_print\f[](3), or by enabling debugging as described under \f[B]DEBUGGING AND ERROR HANDLING\f[] below. The library uses \f[B]pthreads\f[] to be fully MT\-safe, but never creates or destroys threads itself. The library does not make use of any signals, networking, and never calls \f[B]select\f[](2) or \f[B]poll\f[](2). The system memory allocation routines like \f[B]malloc\f[](3) and \f[B]free\f[](3) are used by \f[B]libvmem\f[] for managing a small amount of run\-time state, but applications are allowed to override these calls if necessary (see the description of \f[B]vmem_set_funcs\f[]() below). .PP \f[B]libvmem\f[] interfaces are grouped into three categories: those that manage memory pools, those providing the basic memory allocation functions, and those interfaces less commonly used for managing the overall library behavior. .SH MANAGING LIBRARY BEHAVIOR .PP The \f[B]vmem_check_version\f[]() function is used to see if the installed \f[B]libvmem\f[] supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile\-time version information, supplied by defines in \f[B]\f[], like this: .IP .nf \f[C] reason\ =\ vmem_check_version(VMEM_MAJOR_VERSION, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VMEM_MINOR_VERSION); if\ (reason\ !=\ NULL)\ { \ \ \ \ /*\ version\ check\ failed,\ reason\ string\ tells\ you\ why\ */ } \f[] .fi .PP Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. .PP An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text \f[I]introduced in version x.y\f[] in the section of this manual describing the feature. .PP When the version check is successful, \f[B]vmem_check_version\f[]() returns NULL. Otherwise, \f[B]vmem_check_version\f[]() returns a static string describing the reason for failing the version check. The returned string must not be modified or freed. .PP The \f[B]vmem_set_funcs\f[]() function allows an application to override some interfaces used internally by \f[B]libvmem\f[]. Passing NULL for any of the handlers will cause the \f[B]libvmem\f[] default function to be used. The only functions in the malloc family used by the library are represented by the first four arguments to \f[B]vmem_set_funcs\f[](). While the library does not make heavy use of the system malloc functions, it does allocate approximately 4\-8 kilobytes for each memory pool in use. The \f[I]print_func\f[] function is called by \f[B]libvmem\f[] when the \f[B]vmem_stats_print\f[]() entry point is used, or when additional tracing is enabled in the debug version of the library as described in \f[B]DEBUGGING AND ERROR HANDLING\f[], below. The default \f[I]print_func\f[] used by the library prints to the file specified by the \f[B]VMEM_LOG_FILE\f[] environment variable, or to \f[I]stderr\f[] if that variable is not set. .SH CAVEATS .PP \f[B]libvmem\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH DEBUGGING AND ERROR HANDLING .PP If an error is detected during the call to a \f[B]libvmem\f[] function, the application may retrieve an error message describing the reason for the failure from \f[B]vmem_errormsg\f[](). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If \f[I]errno\f[] was set, the error message may include a description of the corresponding error code as returned by \f[B]strerror\f[](3). The error message buffer is thread\-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a \f[B]libvmem\f[] function indicated an error, or if \f[I]errno\f[] was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. .PP Two versions of \f[B]libvmem\f[] are typically available on a development system. The normal version is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. A second version, accessed when using libraries from \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the \f[B]LD_LIBRARY_PATH\f[] environment variable to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]VMEM_LOG_LEVEL\f[] .PP The value of \f[B]VMEM_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- Tracing is disabled. This is the default level when \f[B]VMEM_LOG_LEVEL\f[] is not set. Only statistics are logged, and then only in response to a call to \f[B]vmem_stats_print\f[](). .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous tracing information about all memory allocations and deallocations. .PP Unless \f[B]VMEM_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]VMEM_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]VMEM_LOG_FILE\f[] is not set, output is written to \f[I]stderr\f[]. .SH EXAMPLE .PP The following example creates a memory pool, allocates some memory to contain the string \[lq]hello, world\[rq], and then frees that memory. .IP .nf \f[C] #include\ #include\ #include\ #include\ int main(int\ argc,\ char\ *argv[]) { \ \ \ \ VMEM\ *vmp; \ \ \ \ char\ *ptr; \ \ \ \ /*\ create\ minimum\ size\ pool\ of\ memory\ */ \ \ \ \ if\ ((vmp\ =\ vmem_create("/pmem\-fs", \ \ \ \ \ \ \ \ \ \ \ \ VMEM_MIN_POOL))\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror("vmem_create"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ if\ ((ptr\ =\ vmem_malloc(vmp,\ 100))\ ==\ NULL)\ { \ \ \ \ \ \ \ \ perror("vmem_malloc"); \ \ \ \ \ \ \ \ exit(1); \ \ \ \ } \ \ \ \ strcpy(ptr,\ "hello,\ world"); \ \ \ \ /*\ give\ the\ memory\ back\ */ \ \ \ \ vmem_free(vmp,\ ptr); \ \ \ \ /*\ ...\ */ \ \ \ \ vmem_delete(vmp); } \f[] .fi .PP See for more examples using the \f[B]libvmem\f[] API. .SH BUGS .PP Unlike the normal \f[B]malloc\f[](3), which asks the system for additional memory when it runs out, \f[B]libvmem\f[] allocates the size it is told to and never attempts to grow or shrink that memory pool. .SH ACKNOWLEDGEMENTS .PP \f[B]libvmem\f[] depends on jemalloc, written by Jason Evans, to do the heavy lifting of managing dynamic memory allocation. See: .PP \f[B]libvmem\f[] builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: .SH SEE ALSO .PP \f[B]mmap\f[](2), \f[B]dlclose\f[](3), \f[B]malloc\f[](3), \f[B]strerror\f[](3), \f[B]vmem_create\f[](3), \f[B]vmem_malloc\f[](3), and \f[B]\f[] .PP On Linux: .PP \f[B]jemalloc\f[](3), \f[B]pthreads\f[](7) .PP On FreeBSD: .PP \f[B]pthread\f[](3) pmdk-1.4.1/doc/generated/libvmmalloc.7000066400000000000000000000302171331545616200175550ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "LIBVMMALLOC" "7" "2018-05-21" "PMDK - vmmalloc API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]libvmmalloc\f[] \[en] general purpose volatile memory allocation library .SH SYNOPSIS .IP .nf \f[C] $\ LD_PRELOAD=libvmmalloc.so\ command\ [\ args...\ ] \f[] .fi .PP or .IP .nf \f[C] #include\ #ifndef\ __FreeBSD__ \ \ \ \ #include\ #else \ \ \ \ #include\ #endif #include\ cc\ [\ flag...\ ]\ file...\ \-lvmmalloc\ [\ library...\ ] \f[] .fi .IP .nf \f[C] void\ *malloc(size_t\ size); void\ free(void\ *ptr); void\ *calloc(size_t\ number,\ size_t\ size); void\ *realloc(void\ *ptr,\ size_t\ size); int\ posix_memalign(void\ **memptr,\ size_t\ alignment,\ size_t\ size); void\ *aligned_alloc(size_t\ alignment,\ size_t\ size); void\ *memalign(size_t\ alignment,\ size_t\ size); void\ *valloc(size_t\ size); void\ *pvalloc(size_t\ size); size_t\ malloc_usable_size(const\ void\ *ptr); void\ cfree(void\ *ptr); \f[] .fi .SH DESCRIPTION .PP \f[B]libvmmalloc\f[] transparently converts all dynamic memory allocations into Persistent Memory allocations. .PP The typical usage of \f[B]libvmmalloc\f[] does not require any modification of the target program. It is enough to load \f[B]libvmmalloc\f[] before all other libraries by setting the environment variable \f[B]LD_PRELOAD\f[]. When used in that way, \f[B]libvmmalloc\f[] interposes the standard system memory allocation routines, as defined in \f[B]malloc\f[](3), \f[B]posix_memalign\f[](3) and \f[B]malloc_usable_size\f[](3), and provides that all dynamic memory allocations are made from a \f[I]memory pool\f[] built on a memory\-mapped file, instead of the system heap. The memory managed by \f[B]libvmmalloc\f[] may have different attributes, depending on the file system containing the memory\-mapped file. In particular, \f[B]libvmmalloc\f[] is part of the \f[I]Persistent Memory Development Kit\f[] because it is sometimes useful to use non\-volatile memory as a volatile memory pool, leveraging its capacity, cost, or performance characteristics. .PP \f[B]libvmmalloc\f[] may be also linked to the program, by providing the **\-lvmmalloc* argument to the linker. Then it becomes the default memory allocator for the program. .RS .PP NOTE: Due to the fact the library operates on a memory\-mapped file, \f[B]it may not work properly with programs that perform fork(2) not followed by exec(3).\f[] There are two variants of experimental \f[B]fork\f[](2) support available in libvmmalloc. The desired library behavior may be selected by setting the \f[B]VMMALLOC_FORK\f[] environment variable. By default variant #1 is enabled. See \f[B]ENVIRONMENT\f[] for more details. .RE .PP \f[B]libvmmalloc\f[] uses the \f[B]mmap\f[](2) system call to create a pool of volatile memory. The library is most useful when used with \f[I]Direct Access\f[] storage (DAX), which is memory\-addressable persistent storage that supports load/store access without being paged via the system page cache. A Persistent Memory\-aware file system is typically used to provide this type of access. Memory\-mapping a file from a Persistent Memory\-aware file system provides the raw memory pools, and this library supplies the traditional \f[I]malloc\f[] interfaces on top of those pools. .PP The memory pool acting as a system heap replacement is created automatically at library initialization time. The user may control its location and size by setting the environment variables described in \f[B]ENVIRONMENT\f[], below. The allocated file space is reclaimed when the process terminates or in case of system crash. .PP Under normal usage, \f[B]libvmmalloc\f[] will never print messages or intentionally cause the process to exit. The library uses \f[B]pthreads\f[](7) to be fully MT\-safe, but never creates or destroys threads itself. The library does not make use of any signals, networking, and never calls \f[B]select\f[](2) or \f[B]poll\f[](2). .SH ENVIRONMENT .PP The \f[B]VMMALLOC_POOL_DIR\f[] and \f[B]VMMALLOC_POOL_SIZE\f[] environment variables \f[B]must\f[] be set for \f[B]libvmmalloc\f[] to work properly. If either of them is not specified, or if their values are not valid, the library prints an appropriate error message and terminates the process. Any other environment variables are optional. .IP \[bu] 2 \f[B]VMMALLOC_POOL_DIR\f[]=\f[I]path\f[] .PP Specifies a path to the directory where the memory pool file should be created. The directory must exist and be writable. .IP \[bu] 2 \f[B]VMMALLOC_POOL_SIZE\f[]=\f[I]len\f[] .PP Defines the desired size (in bytes) of the memory pool file. It must be not less than the minimum allowed size \f[B]VMMALLOC_MIN_POOL\f[] as defined in \f[B]\f[]. .RS .PP NOTE: Due to the fact the library adds some metadata to the memory pool, the amount of actual usable space is typically less than the size of the memory pool file. .RE .IP \[bu] 2 \f[B]VMMALLOC_FORK\f[]=\f[I]val\f[] (EXPERIMENTAL) .PP \f[B]VMMALLOC_FORK\f[] controls the behavior of \f[B]libvmmalloc\f[] in case of \f[B]fork\f[](3), and can be set to the following values: .IP \[bu] 2 \f[B]0\f[] \- \f[B]fork\f[](2) support is disabled. The behavior of \f[B]fork\f[](2) is undefined in this case, but most likely results in memory pool corruption and a program crash due to segmentation fault. .IP \[bu] 2 \f[B]1\f[] \- The memory pool file is remapped with the \f[B]MAP_PRIVATE\f[] flag before the fork completes. From this moment, any access to memory that modifies the heap pages, both in the parent and in the child process, will trigger creation of a copy of those pages in RAM (copy\-on\-write). The benefit of this approach is that it does not significantly increase the time of the initial fork operation, and does not require additional space on the file system. However, all subsequent memory allocations, and modifications of any memory allocated before fork, will consume system memory resources instead of the memory pool. .PP This is the default option if \f[B]VMMALLOC_FORK\f[] is not set. .IP \[bu] 2 \f[B]2\f[] \- A copy of the entire memory pool file is created for the use of the child process. This requires additional space on the file system, but both the parent and the child process may still operate on their memory pools, not consuming system memory resources. .RS .PP NOTE: In case of large memory pools, creating a copy of the pool file may stall the fork operation for a quite long time. .RE .IP \[bu] 2 \f[B]3\f[] \- The library first attempts to create a copy of the memory pool (as for option #2), but if it fails (i.e.\ because of insufficient free space on the file system), it will fall back to option #1. .RS .PP NOTE: Options \f[B]2\f[] and \f[B]3\f[] are not currently supported on FreeBSD. .RE .PP Environment variables used for debugging are described in \f[B]DEBUGGING\f[], below. .SH CAVEATS .PP \f[B]libvmmalloc\f[] relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH DEBUGGING .PP Two versions of \f[B]libvmmalloc\f[] are typically available on a development system. The normal version is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run\-time assertions. A second version, accessed when using libraries from \f[B]/usr/lib/pmdk_debug\f[], contains run\-time assertions and trace points. The typical way to access the debug version is to set the \f[B]LD_LIBRARY_PATH\f[] environment variable to \f[B]/usr/lib/pmdk_debug\f[] or \f[B]/usr/lib64/pmdk_debug\f[], as appropriate. Debugging output is controlled using the following environment variables. These variables have no effect on the non\-debug version of the library. .IP \[bu] 2 \f[B]VMMALLOC_LOG_LEVEL\f[] .PP The value of \f[B]VMMALLOC_LOG_LEVEL\f[] enables trace points in the debug version of the library, as follows: .IP \[bu] 2 \f[B]0\f[] \- Tracing is disabled. This is the default level when \f[B]VMMALLOC_LOG_LEVEL\f[] is not set. .IP \[bu] 2 \f[B]1\f[] \- Additional details on any errors detected are logged, in addition to returning the \f[I]errno\f[]\-based errors as usual. .IP \[bu] 2 \f[B]2\f[] \- A trace of basic operations is logged. .IP \[bu] 2 \f[B]3\f[] \- Enables a very verbose amount of function call tracing in the library. .IP \[bu] 2 \f[B]4\f[] \- Enables voluminous tracing information about all memory allocations and deallocations. .PP Unless \f[B]VMMALLOC_LOG_FILE\f[] is set, debugging output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]VMMALLOC_LOG_FILE\f[] .PP Specifies the name of a file where all logging information should be written. If the last character in the name is \[lq]\-\[rq], the \f[I]PID\f[] of the current process will be appended to the file name when the log file is created. If \f[B]VMMALLOC_LOG_FILE\f[] is not set, output is written to \f[I]stderr\f[]. .IP \[bu] 2 \f[B]VMMALLOC_LOG_STATS\f[] .PP Setting \f[B]VMMALLOC_LOG_STATS\f[] to 1 enables logging human\-readable summary statistics at program termination. .SH NOTES .PP Unlike the normal \f[B]malloc\f[](3), which asks the system for additional memory when it runs out, \f[B]libvmmalloc\f[] allocates the size it is told to and never attempts to grow or shrink that memory pool. .SH BUGS .PP \f[B]libvmmalloc\f[] may not work properly with programs that perform \f[B]fork\f[](2) and do not call \f[B]exec\f[](3) immediately afterwards. See \f[B]ENVIRONMENT\f[] for more details about experimental \f[B]fork\f[](2) support. .PP If logging is enabled in the debug version of the library and the process performs \f[B]fork\f[](2), no new log file is created for the child process, even if the configured log file name ends with \[lq]\-\[rq]. All logging information from the child process will be written to the log file owned by the parent process, which may lead to corruption or partial loss of log data. .PP Malloc hooks (see \f[B]malloc_hook\f[](3)), are not supported when using \f[B]libvmmalloc\f[]. .SH ACKNOWLEDGEMENTS .PP \f[B]libvmmalloc\f[] depends on jemalloc, written by Jason Evans, to do the heavy lifting of managing dynamic memory allocation. See: .SH SEE ALSO .PP \f[B]fork\f[](2), \f[B]dlclose(3)\f[], \f[B]exec\f[](3), \f[B]malloc\f[](3), \f[B]malloc_usable_size\f[](3), \f[B]posix_memalign\f[](3), \f[B]libpmem\f[](7), \f[B]libvmem\f[](7) and \f[B]\f[] .PP On Linux: .PP \f[B]jemalloc\f[](3), \f[B]malloc_hook\f[](3), \f[B]pthreads\f[](7), \f[B]ld.so\f[](8) .PP On FreeBSD: .PP \f[B]ld.so\f[](1), \f[B]pthread\f[](3) pmdk-1.4.1/doc/generated/oid_equals.3000066400000000000000000000000221331545616200173640ustar00rootroot00000000000000.so oid_is_null.3 pmdk-1.4.1/doc/generated/oid_instanceof.3000066400000000000000000000000231331545616200202240ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/oid_is_null.3000066400000000000000000000145711331545616200175550ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "OID_IS_NULL" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]OID_IS_NULL\f[](), \f[B]OID_EQUALS\f[](), \f[B]pmemobj_direct\f[](), \f[B]pmemobj_oid\f[](), \f[B]pmemobj_type_num\f[](), \f[B]pmemobj_pool_by_oid\f[](), \f[B]pmemobj_pool_by_ptr\f[]() \[en] functions that allow mapping operations between object addresses, object handles, oids or type numbers .SH SYNOPSIS .IP .nf \f[C] #include\ OID_IS_NULL(PMEMoid\ oid) OID_EQUALS(PMEMoid\ lhs,\ PMEMoid\ rhs) void\ *pmemobj_direct(PMEMoid\ oid); PMEMoid\ pmemobj_oid(const\ void\ *addr); uint64_t\ pmemobj_type_num(PMEMoid\ oid); PMEMobjpool\ *pmemobj_pool_by_oid(PMEMoid\ oid); PMEMobjpool\ *pmemobj_pool_by_ptr(const\ void\ *addr); \f[] .fi .SH DESCRIPTION .PP Each object stored in a persistent memory pool is represented by an object handle of type \f[I]PMEMoid\f[]. In practice, such a handle is a unique Object IDentifier (\f[I]OID\f[]) of global scope, which means that two objects from different pools will never have the same \f[I]OID\f[]. The special \f[B]OID_NULL\f[] macro defines a NULL\-like handle that does not represent any object. The size of a single object is limited by \f[B]PMEMOBJ_MAX_ALLOC_SIZE\f[]. Thus an allocation with a requested size greater than this value will fail. .PP An \f[I]OID\f[] cannot be used as a direct pointer to an object. Each time the program attempts to read or write object data, it must obtain the current memory address of the object by converting its \f[I]OID\f[] into a pointer. .PP In contrast to the memory address, the \f[I]OID\f[] value for given object does not change during the life of an object (except for \f[I]realloc\f[]), and remains valid after closing and reopening the pool. For this reason, if an object contains a reference to another persistent object, for example, to build some kind of a linked data structure, the reference must be an \f[I]OID\f[] and not a memory address. .PP \f[B]pmemobj_direct\f[]() returns a pointer to the \f[I]PMEMoid\f[] object with handle \f[I]oid\f[]. .PP \f[B]pmemobj_oid\f[]() returns a \f[I]PMEMoid\f[] handle to the object pointed to by \f[I]addr\f[]. .PP \f[B]pmemobj_type_num\f[]() returns the type number of the \f[I]PMEMoid\f[] object with handle \f[I]oid\f[]. .PP \f[B]pmemobj_pool_by_oid\f[]() returns a \f[I]PMEMobjpool\f[]* handle to the pool containing the \f[I]PMEMoid\f[] object with handle \f[I]oid\f[]. .PP \f[B]pmemobj_pool_by_ptr\f[]() returns a \f[I]PMEMobjpool\f[]* handle to the pool containing the address \f[I]addr\f[]. .PP At the time of allocation (or reallocation), each object may be assigned a number representing its type. Such a \f[I]type number\f[] may be used to arrange the persistent objects based on their actual user\-defined structure type, thus facilitating implementation of a simple run\-time type safety mechanism. This also allows iterating through all the objects of a given type that are stored in the persistent memory pool. See \f[B]pmemobj_first\f[](3) for more information. .PP The \f[B]OID_IS_NULL\f[]() macro checks if \f[I]PMEMoid\f[] represents a NULL object. .PP The \f[B]OID_EQUALS\f[]() macro compares two \f[I]PMEMoid\f[] objects. .SH RETURN VALUE .PP The \f[B]pmemobj_direct\f[]() function returns a pointer to the object represented by \f[I]oid\f[]. If \f[I]oid\f[] is \f[B]OID_NULL\f[], \f[B]pmemobj_direct\f[]() returns NULL. .PP The \f[B]pmemobj_oid\f[]() function returns a \f[I]PMEMoid\f[] handle to the object pointed to by \f[I]addr\f[]. If \f[I]addr\f[] is not from within a pmemobj pool, \f[B]OID_NULL\f[] is returned. If \f[I]addr\f[] is not the start of an object (does not point to the beginning of a valid allocation), the resulting \f[I]PMEMoid\f[] can be safely used only with: .IP \[bu] 2 \f[B]pmemobj_pool_by_oid\f[]() .IP \[bu] 2 \f[B]pmemobj_direct\f[]() .IP \[bu] 2 \f[B]pmemobj_tx_add_range\f[](3) .PP The \f[B]pmemobj_type_num\f[]() function returns the type number of the object represented by \f[I]oid\f[]. .PP The \f[B]pmemobj_pool_by_oid\f[]() function returns a handle to the pool that contains the object represented by \f[I]oid\f[]. If the the pool is not open or \f[I]oid\f[] is \f[B]OID_NULL\f[], \f[B]pmemobj_pool_by_oid\f[]() returns NULL. .PP The \f[B]pmemobj_pool_by_ptr\f[]() function returns a handle to the pool that contains the address, or NULL if the address does not belong to any open pool. .SH NOTES .PP For performance reasons, on Linux and FreeBSD the \f[B]pmemobj_direct\f[]() function is inlined by default. To use the non\-inlined variant of \f[B]pmemobj_direct\f[](), define \f[B]PMEMOBJ_DIRECT_NON_INLINE\f[] prior to the \f[I]#include\f[] of \f[B]\f[], either with \f[I]#define\f[] or with the \f[I]\-D\f[] option to the compiler. .SH SEE ALSO .PP \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmem_check_version.3000066400000000000000000000000231331545616200211000ustar00rootroot00000000000000.so man7/libpmem.7 pmdk-1.4.1/doc/generated/pmem_deep_drain.3000066400000000000000000000000211331545616200203460ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_deep_flush.3000066400000000000000000000000211331545616200203720ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_deep_persist.3000066400000000000000000000000211331545616200207420ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_drain.3000066400000000000000000000000211331545616200173510ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_errormsg.3000066400000000000000000000000231331545616200201160ustar00rootroot00000000000000.so man7/libpmem.7 pmdk-1.4.1/doc/generated/pmem_flush.3000066400000000000000000000222461331545616200174120ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEM_FLUSH" "3" "2018-05-21" "PMDK - pmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmem_flush\f[](), \f[B]pmem_drain\f[](), \f[B]pmem_persist\f[](), \f[B]pmem_msync\f[](), \f[B]pmem_deep_flush\f[](), \f[B]pmem_deep_drain\f[](), \f[B]pmem_deep_persist\f[](), \f[B]pmem_has_hw_drain\f[](), \f[B]pmem_has_auto_flush\f[]() \[en] check persistency, store persistent data and delete mappings .SH SYNOPSIS .IP .nf \f[C] #include\ void\ pmem_persist(const\ void\ *addr,\ size_t\ len); int\ pmem_msync(const\ void\ *addr,\ size_t\ len); void\ pmem_flush(const\ void\ *addr,\ size_t\ len); void\ pmem_deep_flush(const\ void\ *addr,\ size_t\ len);\ (EXPERIMENTAL) int\ pmem_deep_drain(const\ void\ *addr,\ size_t\ len);\ (EXPERIMENTAL) int\ pmem_deep_persist(const\ void\ *addr,\ size_t\ len);\ (EXPERIMENTAL) void\ pmem_drain(void); int\ pmem_has_auto_flush(void);\ (EXPERIMENTAL) int\ pmem_has_hw_drain(void); \f[] .fi .SH DESCRIPTION .PP The functions in this section provide access to the stages of flushing to persistence, for the less common cases where an application needs more control of the flushing operations than the \f[B]pmem_persist\f[]() function. .RS .PP WARNING: Using \f[B]pmem_persist\f[]() on a range where \f[B]pmem_is_pmem\f[](3) returns false may not do anything useful \[en] use \f[B]msync\f[](2) instead. .RE .PP The \f[B]pmem_persist\f[]() function force any changes in the range [\f[I]addr\f[], \f[I]addr\f[]+\f[I]len\f[]) to be stored durably in persistent memory. This is equivalent to calling \f[B]msync\f[](2) but may be more optimal and will avoid calling into the kernel if possible. There are no alignment restrictions on the range described by \f[I]addr\f[] and \f[I]len\f[], but \f[B]pmem_persist\f[]() may expand the range as necessary to meet platform alignment requirements. .RS .PP WARNING: Like \f[B]msync\f[](2), there is nothing atomic or transactional about this call. Any unwritten stores in the given range will be written, but some stores may have already been written by virtue of normal cache eviction/replacement policies. Correctly written code must not depend on stores waiting until \f[B]pmem_persist\f[]() is called to become persistent \[en] they can become persistent at any time before \f[B]pmem_persist\f[]() is called. .RE .PP The \f[B]pmem_msync\f[]() function is like \f[B]pmem_persist\f[]() in that it forces any changes in the range [\f[I]addr\f[], \f[I]addr\f[]+\f[I]len\f[]) to be stored durably. Since it calls \f[B]msync\f[](), this function works on either persistent memory or a memory mapped file on traditional storage. \f[B]pmem_msync\f[]() takes steps to ensure the alignment of addresses and lengths passed to \f[B]msync\f[]() meet the requirements of that system call. It calls \f[B]msync\f[]() with the \f[B]MS_SYNC\f[] flag as described in \f[B]msync\f[](2). Typically the application only checks for the existence of persistent memory once, and then uses that result throughout the program, for example: .IP .nf \f[C] /*\ do\ this\ call\ once,\ after\ the\ pmem\ is\ memory\ mapped\ */ int\ is_pmem\ =\ pmem_is_pmem(rangeaddr,\ rangelen); /*\ ...\ make\ changes\ to\ a\ range\ of\ pmem\ ...\ */ /*\ make\ the\ changes\ durable\ */ if\ (is_pmem) \ \ \ \ pmem_persist(subrangeaddr,\ subrangelen); else \ \ \ \ pmem_msync(subrangeaddr,\ subrangelen); /*\ ...\ */ \f[] .fi .RS .PP WARNING: On Linux, \f[B]pmem_msync\f[]() and \f[B]msync\f[](2) have no effect on memory ranges mapped from Device DAX. In case of memory ranges where \f[B]pmem_is_pmem\f[](3) returns true use \f[B]pmem_persist\f[]() to force the changes to be stored durably in persistent memory. .RE .PP The \f[B]pmem_flush\f[]() and \f[B]pmem_drain\f[]() functions provide partial versions of the \f[B]pmem_persist\f[]() function. \f[B]pmem_persist\f[]() can be thought of as this: .IP .nf \f[C] void pmem_persist(const\ void\ *addr,\ size_t\ len) { \ \ \ \ /*\ flush\ the\ processor\ caches\ */ \ \ \ \ pmem_flush(addr,\ len); \ \ \ \ /*\ wait\ for\ any\ pmem\ stores\ to\ drain\ from\ HW\ buffers\ */ \ \ \ \ pmem_drain(); } \f[] .fi .PP These functions allow advanced programs to create their own variations of \f[B]pmem_persist\f[](). For example, a program that needs to flush several discontiguous ranges can call \f[B]pmem_flush\f[]() for each range and then follow up by calling \f[B]pmem_drain\f[]() once. .PP The semantics of \f[B]pmem_deep_flush\f[]() function is the same as \f[B]pmem_flush\f[]() function except that \f[B]pmem_deep_flush\f[]() is indifferent to \f[B]PMEM_NO_FLUSH\f[] environment variable (see \f[B]ENVIRONMENT\f[] section in \f[B]libpmem\f[](7)) and always flushes processor caches. .PP The behavior of \f[B]pmem_deep_persist\f[]() function is the same as \f[B]pmem_persist\f[](), except that it provides higher reliability by flushing persistent memory stores to the most reliable persistence domain available to software rather than depending on automatic WPQ (write pending queue) flush on power failure (ADR). .PP The \f[B]pmem_deep_flush\f[]() and \f[B]pmem_deep_drain\f[]() functions provide partial varsions of \f[B]pmem_deep_persist\f[]() function. \f[B]pmem_deep_persist\f[]() can be thought of as this: .IP .nf \f[C] int\ pmem_deep_persist(const\ void\ *addr,\ size_t\ len) { \ \ \ \ /*\ flush\ the\ processor\ caches\ */ \ \ \ \ pmem_deep_flush(addr,\ len); \ \ \ \ /*\ wait\ for\ any\ pmem\ stores\ to\ drain\ from\ HW\ buffers\ */ \ \ \ \ return\ pmem_deep_drain(addr,\ len); } \f[] .fi .PP Since this operation is usually much more expensive than \f[B]pmem_persist\f[](), it should be used rarely. Typically the application should use this function only to flush the most critical data, which are required to recover after the power failure. .PP The \f[B]pmem_has_auto_flush\f[]() function checks if the machine supports automatic CPU cache flush on power failure or system crash. Function returns true only when each NVDIMM in the system is covered by this mechanism. .PP The \f[B]pmem_has_hw_drain\f[]() function checks if the machine supports an explicit \f[I]hardware drain\f[] instruction for persistent memory. .SH RETURN VALUE .PP The \f[B]pmem_persist\f[]() function returns no value. .PP The \f[B]pmem_msync\f[]() return value is the return value of \f[B]msync\f[](), which can return \-1 and set \f[I]errno\f[] to indicate an error. .PP The \f[B]pmem_flush\f[](), \f[B]pmem_drain\f[]() and \f[B]pmem_deep_flush\f[]() functions return no value. .PP The \f[B]pmem_deep_persist\f[]() and \f[B]pmem_deep_drain\f[]() return 0 on success. Otherwise it returns \-1 and sets \f[I]errno\f[] appropriately. If \f[I]len\f[] is equal zero \f[B]pmem_deep_persist\f[]() and \f[B]pmem_deep_drain\f[]() return 0 but no flushing take place. .PP The \f[B]pmem_has_auto_flush\f[]() function returns 1 if given platform supports processor cache flushing on a power loss event. Otherwise it returns 0. On error it returns \-1 and sets \f[I]errno\f[] appropriately. .PP The \f[B]pmem_has_hw_drain\f[]() function returns true if the machine supports an explicit \f[I]hardware drain\f[] instruction for persistent memory. On Intel processors with persistent memory, stores to persistent memory are considered persistent once they are flushed from the CPU caches, so this function always returns false. Despite that, programs using \f[B]pmem_flush\f[]() to flush ranges of memory should still follow up by calling \f[B]pmem_drain\f[]() once to ensure the flushes are complete. As mentioned above, \f[B]pmem_persist\f[]() handles calling both \f[B]pmem_flush\f[]() and \f[B]pmem_drain\f[](). .SH SEE ALSO .PP \f[B]msync\f[](2), \f[B]pmem_is_pmem\f[](3), \f[B]libpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmem_has_auto_flush.3000066400000000000000000000000211331545616200212600ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_has_hw_drain.3000066400000000000000000000000211331545616200207020ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_is_pmem.3000066400000000000000000000210771331545616200177230ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEM_IS_PMEM" "3" "2018-05-21" "PMDK - pmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmem_is_pmem\f[](), \f[B]pmem_map_file\f[](), \f[B]pmem_unmap\f[]() \[en] check persistency, create and delete mappings .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmem_is_pmem(const\ void\ *addr,\ size_t\ len); void\ *pmem_map_file(const\ char\ *path,\ size_t\ len,\ int\ flags, \ \ \ \ mode_t\ mode,\ size_t\ *mapped_lenp,\ int\ *is_pmemp); int\ pmem_unmap(void\ *addr,\ size_t\ len); \f[] .fi .SH DESCRIPTION .PP Most pmem\-aware applications will take advantage of higher level libraries that alleviate the need for the application to call into \f[B]libpmem\f[] directly. Application developers that wish to access raw memory mapped persistence directly (via \f[B]mmap\f[](2)) and that wish to take on the responsibility for flushing stores to persistence will find the functions described in this section to be the most commonly used. .PP The \f[B]pmem_is_pmem\f[]() function detects if the entire range [\f[I]addr\f[], \f[I]addr\f[]+\f[I]len\f[]) consists of persistent memory. The implementation of \f[B]pmem_is_pmem\f[]() requires a non\-trivial amount of work to determine if the given range is entirely persistent memory. For this reason, it is better to call \f[B]pmem_is_pmem\f[]() once when a range of memory is first encountered, save the result, and use the saved result to determine whether \f[B]pmem_persist\f[](3) or \f[B]msync\f[](2) is appropriate for flushing changes to persistence. Calling \f[B]pmem_is_pmem\f[]() each time changes are flushed to persistence will not perform well. .PP The \f[B]pmem_map_file\f[]() function creates a new read/write mapping for a file. If \f[B]PMEM_FILE_CREATE\f[] is not specified in \f[I]flags\f[], the entire existing file \f[I]path\f[] is mapped, \f[I]len\f[] must be zero, and \f[I]mode\f[] is ignored. Otherwise, \f[I]path\f[] is opened or created as specified by \f[I]flags\f[] and \f[I]mode\f[], and \f[I]len\f[] must be non\-zero. \f[B]pmem_map_file\f[]() maps the file using \f[B]mmap\f[](2), but it also takes extra steps to make large page mappings more likely. .PP On success, \f[B]pmem_map_file\f[]() returns a pointer to the mapped area. If \f[I]mapped_lenp\f[] is not NULL, the length of the mapping is stored into *\f[I]mapped_lenp\f[]. If \f[I]is_pmemp\f[] is not NULL, a flag indicating whether the mapped file is actual pmem, or if \f[B]msync\f[]() must be used to flush writes for the mapped range, is stored into *\f[I]is_pmemp\f[]. .PP The \f[I]flags\f[] argument is 0 or the bitwise OR of one or more of the following file creation flags: .IP \[bu] 2 \f[B]PMEM_FILE_CREATE\f[] \- Create the file named \f[I]path\f[] if it does not exist. \f[I]len\f[] must be non\-zero and specifies the size of the file to be created. If the file already exists, it will be extended or truncated to \f[I]len.\f[] The new or existing file is then fully allocated to size \f[I]len\f[] using \f[B]posix_fallocate\f[](3). \f[I]mode\f[] specifies the mode to use in case a new file is created (see \f[B]creat\f[](2)). .PP The remaining flags modify the behavior of \f[B]pmem_map_file\f[]() when \f[B]PMEM_FILE_CREATE\f[] is specified. .IP \[bu] 2 \f[B]PMEM_FILE_EXCL\f[] \- If specified in conjunction with \f[B]PMEM_FILE_CREATE\f[], and \f[I]path\f[] already exists, then \f[B]pmem_map_file\f[]() will fail with \f[B]EEXIST\f[]. Otherwise, has the same meaning as \f[B]O_EXCL\f[] on \f[B]open\f[](2), which is generally undefined. .IP \[bu] 2 \f[B]PMEM_FILE_SPARSE\f[] \- When specified in conjunction with \f[B]PMEM_FILE_CREATE\f[], create a sparse (holey) file using \f[B]ftruncate\f[](2) rather than allocating it using \f[B]posix_fallocate\f[](3). Otherwise ignored. .IP \[bu] 2 \f[B]PMEM_FILE_TMPFILE\f[] \- Create a mapping for an unnamed temporary file. Must be specified with \f[B]PMEM_FILE_CREATE\f[]. \f[I]len\f[] must be non\-zero, \f[I]mode\f[] is ignored (the temporary file is always created with mode 0600), and \f[I]path\f[] must specify an existing directory name. If the underlying file system supports \f[B]O_TMPFILE\f[], the unnamed temporary file is created in the filesystem containing the directory \f[I]path\f[]; if \f[B]PMEM_FILE_EXCL\f[] is also specified, the temporary file may not subsequently be linked into the filesystem (see \f[B]open\f[](2)). Otherwise, the file is created in \f[I]path\f[] and immediately unlinked. .PP The \f[I]path\f[] can point to a Device DAX. In this case only the \f[B]PMEM_FILE_CREATE\f[] and \f[B]PMEM_FILE_SPARSE\f[] flags are valid, but they are both ignored. For Device DAX mappings, \f[I]len\f[] must be equal to either 0 or the exact size of the device. .PP To delete mappings created with \f[B]pmem_map_file\f[](), use \f[B]pmem_unmap\f[](). .PP The \f[B]pmem_unmap\f[]() function deletes all the mappings for the specified address range, and causes further references to addresses within the range to generate invalid memory references. It will use the address specified by the parameter \f[I]addr\f[], where \f[I]addr\f[] must be a previously mapped region. \f[B]pmem_unmap\f[]() will delete the mappings using \f[B]munmap\f[](2). .SH RETURN VALUE .PP The \f[B]pmem_is_pmem\f[]() function returns true only if the entire range [\f[I]addr\f[], \f[I]addr\f[]+\f[I]len\f[]) consists of persistent memory. A true return from \f[B]pmem_is_pmem\f[]() means it is safe to use \f[B]pmem_persist\f[](3) and the related functions to make changes durable for that memory range. See also \f[B]CAVEATS\f[]. .PP On success, \f[B]pmem_map_file\f[]() returns a pointer to the memory\-mapped region and sets *\f[I]mapped_lenp\f[] and *\f[I]is_pmemp\f[] if they are not NULL. On error, it returns NULL, sets \f[I]errno\f[] appropriately, and does not modify *\f[I]mapped_lenp\f[] or *\f[I]is_pmemp\f[]. .PP On success, \f[B]pmem_unmap\f[]() returns 0. On error, it returns \-1 and sets \f[I]errno\f[] appropriately. .SH NOTES .PP On Linux, \f[B]pmem_is_pmem\f[]() returns true only if the entire range is mapped directly from Device DAX (/dev/daxX.Y) without an intervening file system. In the future, as file systems become available that support flushing with \f[B]pmem_persist\f[](3), \f[B]pmem_is_pmem\f[]() will return true as appropriate. .SH CAVEATS .PP The result of \f[B]pmem_is_pmem\f[]() query is only valid for the mappings created using \f[B]pmem_map_file\f[](). For other memory regions, in particular those created by a direct call to \f[B]mmap\f[](2), \f[B]pmem_is_pmem\f[]() always returns false, even if the queried range is entirely persistent memory. .PP Not all file systems support \f[B]posix_fallocate\f[](3). \f[B]pmem_map_file\f[]() will fail if \f[B]PMEM_FILE_CREATE\f[] is specified without \f[B]PMEM_FILE_SPARSE\f[] and the underlying file system does not support \f[B]posix_fallocate\f[](3). .SH SEE ALSO .PP \f[B]creat\f[](2), \f[B]ftruncate\f[](2), \f[B]mmap\f[](2), \f[B]msync\f[](2), \f[B]munmap\f[](2), \f[B]open\f[](2), \f[B]pmem_persist\f[](3), \f[B]posix_fallocate\f[](3), \f[B]libpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmem_map_file.3000066400000000000000000000000231331545616200200320ustar00rootroot00000000000000.so pmem_is_pmem.3 pmdk-1.4.1/doc/generated/pmem_memcpy_nodrain.3000066400000000000000000000000331331545616200212630ustar00rootroot00000000000000.so pmem_memmove_persist.3 pmdk-1.4.1/doc/generated/pmem_memcpy_persist.3000066400000000000000000000000331331545616200213220ustar00rootroot00000000000000.so pmem_memmove_persist.3 pmdk-1.4.1/doc/generated/pmem_memmove_nodrain.3000066400000000000000000000000331331545616200214360ustar00rootroot00000000000000.so pmem_memmove_persist.3 pmdk-1.4.1/doc/generated/pmem_memmove_persist.3000066400000000000000000000126411331545616200215050ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEM_MEMMOVE_PERSIST" "3" "2018-05-21" "PMDK - pmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmem_memmove_persist\f[](), \f[B]pmem_memcpy_persist\f[](), \f[B]pmem_memset_persist\f[](), \f[B]pmem_memmove_nodrain\f[](), \f[B]pmem_memcpy_nodrain\f[](), \f[B]pmem_memset_nodrain\f[]() \[en] functions that provide optimized copying to persistent memory .SH SYNOPSIS .IP .nf \f[C] #include\ void\ *pmem_memmove_persist(void\ *pmemdest,\ const\ void\ *src,\ size_t\ len); void\ *pmem_memcpy_persist(void\ *pmemdest,\ const\ void\ *src,\ size_t\ len); void\ *pmem_memset_persist(void\ *pmemdest,\ int\ c,\ size_t\ len); void\ *pmem_memmove_nodrain(void\ *pmemdest,\ const\ void\ *src,\ size_t\ len); void\ *pmem_memcpy_nodrain(void\ *pmemdest,\ const\ void\ *src,\ size_t\ len); void\ *pmem_memset_nodrain(void\ *pmemdest,\ int\ c,\ size_t\ len); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmem_memmove_persist\f[](), \f[B]pmem_memcpy_persist\f[](), and \f[B]pmem_memset_persist\f[](), functions provide the same memory copying as their namesakes \f[B]memmove\f[](3), \f[B]memcpy\f[](3) and \f[B]memset\f[](3), and ensure that the result has been flushed to persistence before returning. For example, the following code is functionally equivalent to \f[B]pmem_memmove_persist\f[](): .IP .nf \f[C] void\ * pmem_memmove_persist(void\ *pmemdest,\ const\ void\ *src,\ size_t\ len) { \ \ \ \ void\ *retval\ =\ memmove(pmemdest,\ src,\ len); \ \ \ \ pmem_persist(pmemdest,\ len); \ \ \ \ return\ retval; } \f[] .fi .PP Calling \f[B]pmem_memmove_persist\f[]() may out\-perform the above code, however, since the \f[B]libpmem\f[](7) implementation may take advantage of the fact that \f[I]pmemdest\f[] is persistent memory and use instructions such as \f[I]non\-temporal\f[] stores to avoid the need to flush processor caches. .RS .PP WARNING: Using these functions where \f[B]pmem_is_pmem\f[](3) returns false may not do anything useful. Use the normal libc functions in that case. .RE .PP The \f[B]pmem_memmove_nodrain\f[](), \f[B]pmem_memcpy_nodrain\f[]() and \f[B]pmem_memset_nodrain\f[]() functions are similar to \f[B]pmem_memmove_persist\f[](), \f[B]pmem_memcpy_persist\f[](), and \f[B]pmem_memset_persist\f[]() described above, except they skip the final \f[B]pmem_drain\f[]() step. This allows applications to optimize cases where several ranges are being copied to persistent memory, followed by a single call to \f[B]pmem_drain\f[](). The following example illustrates how these functions might be used to avoid multiple calls to \f[B]pmem_drain\f[]() when copying several ranges of memory to pmem: .IP .nf \f[C] /*\ ...\ write\ several\ ranges\ to\ pmem\ ...\ */ pmem_memcpy_nodrain(pmemdest1,\ src1,\ len1); pmem_memcpy_nodrain(pmemdest2,\ src2,\ len2); /*\ ...\ */ /*\ wait\ for\ any\ pmem\ stores\ to\ drain\ from\ HW\ buffers\ */ pmem_drain(); \f[] .fi .SH RETURN VALUE .PP The \f[B]pmem_memmove_persist\f[](), \f[B]pmem_memcpy_persist\f[](), \f[B]pmem_memset_persist\f[](), \f[B]pmem_memmove_nodrain\f[](), \f[B]pmem_memcpy_nodrain\f[]() and \f[B]pmem_memset_nodrain\f[]() functions return the address of the destination. .SH CAVEATS .PP After calling any of the \f[I]_nodrain\f[] functions (\f[B]pmem_memmove_nodrain\f[](), \f[B]pmem_memcpy_nodrain\f[]() or \f[B]pmem_memset_nodrain\f[]()) you should not expect memory to be visible to other threads before calling \f[B]pmem_drain\f[](3) or any of the \f[I]_persist\f[] functions. This is because those functions may use non\-temporal store instructions, which are weakly ordered. See \[lq]Intel 64 and IA\-32 Architectures Software Developer's Manual\[rq], Volume 1, \[lq]Caching of Temporal vs.\ Non\-Temporal Data\[rq] section for details. .SH SEE ALSO .PP \f[B]memcpy\f[](3), \f[B]memmove\f[](3), \f[B]memset\f[](3), \f[B]libpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmem_memset_nodrain.3000066400000000000000000000000331331545616200212630ustar00rootroot00000000000000.so pmem_memmove_persist.3 pmdk-1.4.1/doc/generated/pmem_memset_persist.3000066400000000000000000000000331331545616200213220ustar00rootroot00000000000000.so pmem_memmove_persist.3 pmdk-1.4.1/doc/generated/pmem_msync.3000066400000000000000000000000211331545616200174050ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_persist.3000066400000000000000000000000211331545616200177450ustar00rootroot00000000000000.so pmem_flush.3 pmdk-1.4.1/doc/generated/pmem_unmap.3000066400000000000000000000000231331545616200173760ustar00rootroot00000000000000.so pmem_is_pmem.3 pmdk-1.4.1/doc/generated/pmemblk_bsize.3000066400000000000000000000056361331545616200201020ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMBLK_BSIZE" "3" "2018-05-21" "PMDK - pmemblk API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemblk_bsize\f[](), \f[B]pmemblk_nblock\f[]() \[en] check number of available blocks or usable space in block memory pool .SH SYNOPSIS .IP .nf \f[C] #include\ size_t\ pmemblk_bsize(PMEMblkpool\ *pbp); size_t\ pmemblk_nblock(PMEMblkpool\ *pbp); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemblk_bsize\f[]() function returns the block size of the specified block memory pool, that is, the value which was passed as \f[I]bsize\f[] to \f[B]pmemblk_create\f[](). \f[I]pbp\f[] must be a block memory pool handle as returned by \f[B]pmemblk_open\f[](3) or \f[B]pmemblk_create\f[](3). .PP The \f[B]pmemblk_nblock\f[]() function returns the usable space in the block memory pool. \f[I]pbp\f[] must be a block memory pool handle as returned by \f[B]pmemblk_open\f[](3) or \f[B]pmemblk_create\f[](3). .SH RETURN VALUE .PP The \f[B]pmemblk_bsize\f[]() function returns the block size of the specified block memory pool. .PP The \f[B]pmemblk_nblock\f[]() function returns the usable space in the block memory pool, expressed as the number of blocks available. .SH SEE ALSO .PP \f[B]pmemblk_create\f[](3), \f[B]pmemblk_open\f[](3), \f[B]libpmemblk\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemblk_check.3000066400000000000000000000000251331545616200200260ustar00rootroot00000000000000.so pmemblk_create.3 pmdk-1.4.1/doc/generated/pmemblk_check_version.3000066400000000000000000000000261331545616200215740ustar00rootroot00000000000000.so man7/libpmemblk.7 pmdk-1.4.1/doc/generated/pmemblk_close.3000066400000000000000000000000251331545616200200560ustar00rootroot00000000000000.so pmemblk_create.3 pmdk-1.4.1/doc/generated/pmemblk_create.3000066400000000000000000000207151331545616200202240ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMBLK_CREATE" "3" "2018-05-21" "PMDK - pmemblk API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemblk_create\f[](), \f[B]pmemblk_open\f[](), \f[B]pmemblk_close\f[](), \f[B]pmemblk_check\f[]() \[en] create, open, close and validate block pool .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMblkpool\ *pmemblk_create(const\ char\ *path,\ size_t\ bsize, \ \ \ \ \ \ \ \ size_t\ poolsize,\ mode_t\ mode); PMEMblkpool\ *pmemblk_open(const\ char\ *path,\ size_t\ bsize); void\ pmemblk_close(PMEMblkpool\ *pbp); int\ pmemblk_check(const\ char\ *path,\ size_t\ bsize); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemblk_create\f[]() function creates a block memory pool with the given total \f[I]poolsize\f[], divided into as many elements of size \f[I]bsize\f[] as will fit in the pool. Since the transactional nature of a block memory pool requires some space overhead in the memory pool, the resulting number of available blocks is less than \f[I]poolsize\f[]/\f[I]bsize\f[], and is made available to the caller via the \f[B]pmemblk_nblock\f[](3) function. Given the specifics of the implementation, the number of available blocks for the user cannot be less than 256. This translates to at least 512 internal blocks. \f[I]path\f[] specifies the name of the memory pool file to be created. \f[I]mode\f[] specifies the permissions to use when creating the file, as described by \f[B]creat\f[](2). The memory pool file is fully allocated to the size \f[I]poolsize\f[] using \f[B]posix_fallocate\f[](3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling \f[B]pmemblk_create\f[](), and then specifying \f[I]poolsize\f[] as zero. In this case \f[B]pmemblk_create\f[]() will take the pool size from the size of the existing file, and will verify that the file appears to be empty by searching for any non\-zero data in the pool header at the beginning of the file. The net pool size of a pool file is equal to the file size. The minimum net pool size allowed by the library for a block pool is defined in \f[B]\f[] as \f[B]PMEMBLK_MIN_POOL\f[]. \f[I]bsize\f[] can be any non\-zero value; however, \f[B]libpmemblk\f[] will silently round up the given size to \f[B]PMEMBLK_MIN_BLK\f[], as defined in \f[B]\f[]. .PP Depending on the configuration of the system, the available non\-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemblk memory pool could be limited by the capacity of a single memory device. \f[B]libpmemblk\f[](7) allows building a persistent memory resident array spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a \f[I]pool set\f[] may be stored on a different memory device or pmem\-aware filesystem. .PP Creation of all the parts of the pool set can be done with \f[B]pmemblk_create\f[](); however, the recommended method for creating pool sets is by using the \f[B]pmempool\f[](1) utility. .PP When creating a pool set consisting of multiple files, the \f[I]path\f[] argument passed to \f[B]pmemblk_create\f[]() must point to the special \f[I]set\f[] file that defines the pool layout and the location of all the parts of the pool set. The \f[I]poolsize\f[] argument must be 0. The meaning of the \f[I]mode\f[] argument does not change, except that the same \f[I]mode\f[] is used for creation of all the parts of the pool set. .PP For more information on pool set format, see \f[B]poolset\f[](5). .PP The \f[B]pmemblk_open\f[]() function opens an existing block memory pool. As with \f[B]pmemblk_create\f[](), \f[I]path\f[] must identify either an existing block memory pool file, or the \f[I]set\f[] file used to create a pool set. The application must have permission to open the file and memory map the file or pool set with read/write permissions. If \f[I]bsize\f[] is non\-zero, \f[B]pmemblk_open\f[]() will verify that the given block size matches the block size used when the pool was created. Otherwise, \f[B]pmemblk_open\f[]() will open the pool without verifying the block size. The \f[I]bsize\f[] can be determined using the \f[B]pmemblk_bsize\f[](3) function. .PP The \f[B]pmemblk_close\f[]() function closes the memory pool indicated by \f[I]pbp\f[] and deletes the memory pool handle. The block memory pool itself lives on in the file that contains it and may be re\-opened at a later time using \f[B]pmemblk_open\f[]() as described above. .PP The \f[B]pmemblk_check\f[]() function performs a consistency check of the file indicated by \f[I]path\f[], and returns 1 if the memory pool is found to be consistent. If the pool is found not to be consistent, further use of the file with \f[B]libpmemblk\f[] will result in undefined behavior. The debug version of \f[B]libpmemblk\f[] will provide additional details on inconsistencies when \f[B]PMEMBLK_LOG_LEVEL\f[] is at least 1, as described in the \f[B]DEBUGGING AND ERROR HANDLING\f[] section in \f[B]libpmemblk\f[](7). \f[B]pmemblk_check\f[]() opens the given \f[I]path\f[] read\-only so it never makes any changes to the file. This function is not supported on Device DAX. .SH RETURN VALUE .PP On success, \f[B]pmemblk_create\f[]() returns a \f[I]PMEMblkpool*\f[] handle to the block memory pool. On error, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]pmemblk_open\f[]() returns a \f[I]PMEMblkpool*\f[] handle that can be used with most of the functions in \f[B]libpmemblk\f[](7). On error, it returns NULL and sets \f[I]errno\f[] appropriately. Possible errors include: .IP \[bu] 2 failure to open \f[I]path\f[] .IP \[bu] 2 \f[I]path\f[] specifies a \f[I]set\f[] file and any of the pool set files cannot be opened .IP \[bu] 2 \f[I]path\f[] specifies a \f[I]set\f[] file and the actual size of any file does not match the corresponding part size defined in the \f[I]set\f[] file .IP \[bu] 2 \f[I]bsize\f[] is non\-zero and does not match the block size given when the pool was created. \f[I]errno\f[] is set to \f[B]EINVAL\f[] in this case. .PP The \f[B]pmemblk_close\f[]() function returns no value. .PP \f[B]pmemblk_check\f[]() returns 1 if the memory pool is found to be consistent. If the check is successfully performed but the pool is found to be inconsistent, \f[B]pmemblk_check\f[]() returns 0. This includes the case where \f[I]bsize\f[] is non\-zero and does not match the block size given when the pool was created. If the consistency check cannot be performed, \f[B]pmemblk_check\f[]() returns \-1 and sets \f[I]errno\f[] appropriately. .SH CAVEATS .PP Not all file systems support \f[B]posix_fallocate\f[](3). \f[B]pmemblk_create\f[]() will fail if the underlying file system does not support \f[B]posix_fallocate\f[](3). .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]creat\f[](2), \f[B]pmemblk_nblock\f[](3), \f[B]posix_fallocate\f[](3), \f[B]poolset\f[](5), \f[B]libpmemblk\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemblk_errormsg.3000066400000000000000000000000261331545616200206120ustar00rootroot00000000000000.so man7/libpmemblk.7 pmdk-1.4.1/doc/generated/pmemblk_nblock.3000066400000000000000000000000241331545616200202200ustar00rootroot00000000000000.so pmemblk_bsize.3 pmdk-1.4.1/doc/generated/pmemblk_open.3000066400000000000000000000000251331545616200177120ustar00rootroot00000000000000.so pmemblk_create.3 pmdk-1.4.1/doc/generated/pmemblk_read.3000066400000000000000000000056721331545616200177010ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMBLK_READ" "3" "2018-05-21" "PMDK - pmemblk API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemblk_read\f[](), \f[B]pmemblk_write\f[]() \[en] read or write a block from a block memory pool .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmemblk_read(PMEMblkpool\ *pbp,\ void\ *buf,\ long\ long\ blockno); int\ pmemblk_write(PMEMblkpool\ *pbp,\ const\ void\ *buf,\ long\ long\ blockno); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemblk_read\f[]() function reads the block with block number \f[I]blockno\f[] from memory pool \f[I]pbp\f[] into the buffer \f[I]buf\f[]. Reading a block that has never been written by \f[B]pmemblk_write\f[]() will return a block of zeroes. .PP The \f[B]pmemblk_write\f[]() function writes a block from \f[I]buf\f[] to block number \f[I]blockno\f[] in the memory pool \f[I]pbp\f[]. The write is atomic with respect to other reads and writes. In addition, the write cannot be torn by program failure or system crash; on recovery the block is guaranteed to contain either the old data or the new data, never a mixture of both. .SH RETURN VALUE .PP On success, the \f[B]pmemblk_read\f[]() and \f[B]pmemblk_write\f[]() functions return 0. On error, they return \-1 and set \f[I]errno\f[] appropriately. .SH SEE ALSO .PP \f[B]libpmemblk\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemblk_set_error.3000066400000000000000000000000271331545616200207570ustar00rootroot00000000000000.so pmemblk_set_zero.3 pmdk-1.4.1/doc/generated/pmemblk_set_funcs.3000066400000000000000000000000261331545616200207430ustar00rootroot00000000000000.so man7/libpmemblk.7 pmdk-1.4.1/doc/generated/pmemblk_set_zero.3000066400000000000000000000056041331545616200206130ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMBLK_SET_ZERO" "3" "2018-05-21" "PMDK - pmemblk API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemblk_set_zero\f[](), \f[B]pmemblk_set_error\f[]() \[en] block management functions .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmemblk_set_zero(PMEMblkpool\ *pbp,\ long\ long\ blockno); int\ pmemblk_set_error(PMEMblkpool\ *pbp,\ long\ long\ blockno); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemblk_set_zero\f[]() function writes zeros to block number \f[I]blockno\f[] in persistent memory resident array of blocks \f[I]pbp\f[]. Using this function is faster than actually writing a block of zeros since \f[B]libpmemblk\f[](7) uses metadata to indicate the block should read back as zero. .PP The \f[B]pmemblk_set_error\f[]() function sets the error state for block number \f[I]blockno\f[] in persistent memory resident array of blocks \f[I]pbp\f[]. A block in the error state returns \f[I]errno\f[] \f[B]EIO\f[] when read. Writing the block clears the error state and returns the block to normal use. .SH RETURN VALUE .PP On success, \f[B]pmemblk_set_zero\f[]() and \f[B]pmemblk_set_error\f[]() return 0. On error, they return \-1 and set \f[I]errno\f[] appropriately. .SH SEE ALSO .PP \f[B]libpmemblk\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemblk_write.3000066400000000000000000000000231331545616200201010ustar00rootroot00000000000000.so pmemblk_read.3 pmdk-1.4.1/doc/generated/pmemcto_aligned_alloc.3000066400000000000000000000061751331545616200215570ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_ALIGNED_ALLOC" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_aligned_alloc \[en] allocate aligned memory .SH SYNOPSIS .IP .nf \f[C] #include\ void\ *pmemcto_aligned_alloc(PMEMctopool\ *pcp,\ size_t\ alignment,\ size_t\ size); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_aligned_alloc\f[]() function provides the same semantics as \f[B]aligned_alloc\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It allocates \f[I]size\f[] bytes from the memory pool and returns a pointer to the allocated memory. The memory is not zeroed. The memory address will be a multiple of \f[I]alignment\f[], which must be a power of two. .SH RETURN VALUE .PP On success, \f[B]pmemcto_aligned_alloc\f[]() function returns a pointer to the allocated memory. If \f[I]size\f[] is 0, then \f[B]pmemcto_aligned_alloc\f[]() returns either NULL, or a unique pointer value that can later be successfully passed to \f[B]pmemcto_free\f[](3). If \f[B]pmemcto_aligned_alloc\f[]() is unable to satisfy the allocation request, a NULL pointer is returned and \f[I]errno\f[] is set appropriately. .SH ERRORS .PP \f[B]EINVAL\f[] \f[I]alignment\f[] was not a power of two. .PP \f[B]ENOMEM\f[] Insufficient memory available to satisfy allocation request. .SH SEE ALSO .PP \f[B]aligned_alloc\f[](3), \f[B]malloc\f[](3), \f[B]jemalloc\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_calloc.3000066400000000000000000000000251331545616200202230ustar00rootroot00000000000000.so pmemcto_malloc.3 pmdk-1.4.1/doc/generated/pmemcto_check.3000066400000000000000000000000231331545616200200410ustar00rootroot00000000000000.so pmemcto_open.3 pmdk-1.4.1/doc/generated/pmemcto_check_version.3000066400000000000000000000000261331545616200216110ustar00rootroot00000000000000.so man7/libpmemcto.7 pmdk-1.4.1/doc/generated/pmemcto_close.3000066400000000000000000000000231331545616200200710ustar00rootroot00000000000000.so pmemcto_open.3 pmdk-1.4.1/doc/generated/pmemcto_create.3000066400000000000000000000000231331545616200202270ustar00rootroot00000000000000.so pmemcto_open.3 pmdk-1.4.1/doc/generated/pmemcto_errormsg.3000066400000000000000000000000261331545616200206270ustar00rootroot00000000000000.so man7/libpmemcto.7 pmdk-1.4.1/doc/generated/pmemcto_free.3000066400000000000000000000000251331545616200177070ustar00rootroot00000000000000.so pmemcto_malloc.3 pmdk-1.4.1/doc/generated/pmemcto_get_root_pointer.3000066400000000000000000000000371331545616200223530ustar00rootroot00000000000000.so pmemcto_set_root_pointer.3 pmdk-1.4.1/doc/generated/pmemcto_malloc.3000066400000000000000000000135441331545616200202470ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_MALLOC" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_malloc, pmemcto_free, pmemcto_calloc, pmemcto_realloc \[en] allocate and free persistent memory .SH SYNOPSIS .IP .nf \f[C] #include\ void\ *pmemcto_malloc(PMEMctopool\ *pcp,\ size_t\ size); void\ pmemcto_free(PMEMctopool\ *pcp,\ void\ *ptr); void\ *pmemcto_calloc(PMEMctopool\ *pcp,\ size_t\ nmemb,\ size_t\ size); void\ *pmemcto_realloc(PMEMctopool\ *pcp,\ void\ *ptr,\ size_t\ size); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_malloc\f[]() function provides the same semantics as \f[B]malloc\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It allocates \f[I]size\f[] bytes and returns a pointer to the allocated memory. \f[I]The memory is not initialized\f[]. If \f[I]size\f[] is 0, then \f[B]pmemcto_malloc\f[]() returns either NULL, or a unique pointer value that can later be successfully passed to \f[B]pmemcto_free\f[](). .PP The \f[B]pmemcto_free\f[]() function provides the same semantics as \f[B]free\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It frees the memory space pointed to by \f[I]ptr\f[], which must have been returned by a previous call to \f[B]pmemcto_malloc\f[](), \f[B]pmemcto_calloc\f[]() or \f[B]pmemcto_realloc\f[]() for \f[I]the same pool of memory\f[]. Undefined behavior occurs if frees do not correspond to allocated memory from the same memory pool. If \f[I]ptr\f[] is NULL, no operation is performed. .PP The \f[B]pmemcto_calloc\f[]() function provides the same semantics as \f[B]calloc\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It allocates memory for an array of \f[I]nmemb\f[] elements of \f[I]size\f[] bytes each and returns a pointer to the allocated memory. The memory is set to zero. If \f[I]nmemb\f[] or \f[I]size\f[] is 0, then \f[B]pmemcto_calloc\f[]() returns either NULL, or a unique pointer value that can later be successfully passed to \f[B]pmemcto_free\f[](). .PP The \f[B]pmemcto_realloc\f[]() function provides the same semantics as \f[B]realloc\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It changes the size of the memory block pointed to by \f[I]ptr\f[] to \f[I]size\f[] bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will \f[I]not\f[] be initialized. If \f[I]ptr\f[] is NULL, then the call is equivalent to \f[I]pmemcto_malloc(pcp, size)\f[], for all values of \f[I]size\f[]; if \f[I]size\f[] is equal to zero and \f[I]ptr\f[] is not NULL, then the call is equivalent to \f[I]pmemcto_free(pcp, ptr)\f[]. Unless \f[I]ptr\f[] is NULL, it must have been returned by an earlier call to \f[B]pmemcto_malloc\f[](), \f[B]pmemcto_calloc\f[](), \f[B]pmemcto_realloc\f[]() or \f[B]pmemcto_aligned_alloc\f[](3). If the area pointed to was moved, a \f[I]pmemcto_free(pcp, ptr)\f[] is done. .SH RETURN VALUE .PP On success, \f[B]pmemcto_malloc\f[]() and \f[B]pmemcto_calloc\f[]() functions return a pointer to the allocated memory. If the allocation request cannot be satisfied, a NULL pointer is returned and \f[I]errno\f[] is set appropriately. .PP The \f[B]pmemcto_free\f[]() function returns no value. .PP On success, \f[B]pmemcto_realloc\f[]() function returns a pointer to the newly allocated memory, or NULL if it is unable to satisfy the allocation request. If \f[I]size\f[] was equal to 0, either NULL or a pointer suitable to be passed to \f[B]pmemcto_free\f[]() is returned. If \f[B]pmemcto_realloc\f[]() fails the original block is left untouched; it is not freed or moved. .SH ERRORS .PP \f[B]ENOMEM\f[] Insufficient memory available to satisfy allocation request. .SH NOTES .PP Unlike the normal \f[B]malloc\f[](), which asks the system for additional memory when it runs out, \f[B]libpmemcto\f[](7) allocates the size it is told to and never attempts to grow or shrink that memory pool. .SH SEE ALSO .PP \f[B]jemalloc\f[](3), \f[B]malloc\f[](3), \f[B]pmemcto_aligned_alloc\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_malloc_usable_size.3000066400000000000000000000054031331545616200226270ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_MALLOC_USABLE_SIZE" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_malloc_usable_size \[en] obtain size of block of memory allocated from pool .SH SYNOPSIS .IP .nf \f[C] #include\ size_t\ pmemcto_malloc_usable_size(PMEMctopool\ *pcp,\ void\ *ptr); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_malloc_usable_size\f[]() function provides the same semantics as \f[B]malloc_usable_size\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It returns the number of usable bytes in the block of allocated memory pointed to by \f[I]ptr\f[], a pointer to a block of memory allocated by \f[B]pmemcto_malloc\f[](3) or a related function. .SH RETURN VALUE .PP The \f[B]pmemcto_malloc_usable_size\f[]() function returns the number of usable bytes in the block of allocated memory pointed to by \f[I]ptr\f[]. If \f[I]ptr\f[] is NULL, 0 is returned. .SH SEE ALSO .PP \f[B]jemalloc\f[](3), \f[B]malloc\f[](3), \f[B]malloc_usable_size\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_open.3000066400000000000000000000224541331545616200177410ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_OPEN" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemcto_create\f[](), \f[B]pmemcto_open\f[](), \f[B]pmemcto_close\f[](), \f[B]pmemcto_check\f[]() \[en] create, open, close and validate close\-to\-open persistence pool .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMctopool\ *pmemcto_create(const\ char\ *path,\ const\ char\ *layout, \ \ \ \ \ \ \ \ size_t\ poolsize,\ mode_t\ mode); PMEMctopool\ *pmemcto_open(const\ char\ *path,\ const\ char\ *layout); void\ pmemcto_close(PMEMctopool\ *pcp); int\ pmemcto_check(const\ char\ *path,\ const\ char\ *layout); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_create\f[]() function creates a close\-to\-open persistence pool with the given total \f[I]poolsize\f[]. The resulting pool is then used with functions like \f[B]pmemcto_malloc\f[](3) and \f[B]pmemcto_free\f[](3) to provide the familiar \f[I]malloc\-like\f[] programming model for the memory pool. \f[I]path\f[] specifies the name of the memory pool file to be created. \f[I]layout\f[] specifies the application's layout type in the form of a string. The layout name is not interpreted by \f[B]libpmemcto\f[](7), but may be used as a check when \f[B]pmemcto_open\f[]() is called. The layout name, including the terminating null byte (`\\0'), cannot be longer than \f[B]PMEMCTO_MAX_LAYOUT\f[] as defined in \f[B]\f[]. A NULL \f[I]layout\f[] is equivalent to using an empty string as a layout name. \f[I]mode\f[] specifies the permissions to use when creating the file, as described by \f[B]creat\f[](2). The memory pool file is fully allocated to the size \f[I]poolsize\f[] using \f[B]posix_fallocate\f[](3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling \f[B]pmemcto_create\f[](), and then specifying \f[I]poolsize\f[] as zero. In this case \f[B]pmemcto_create\f[]() will take the pool size from the size of the existing file and will verify that the file appears to be empty by searching for any non\-zero data in the pool header at the beginning of the file. The minimum net pool size allowed by the library for a local close\-to\-open persistence pool is defined in \f[B]\f[] as \f[B]PMEMCTO_MIN_POOL\f[]. .PP Depending on the configuration of the system, the available non\-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemcto memory pool could be limited by the capacity of a single memory device. \f[B]libpmemcto\f[](7) allows building a close\-to\-open persistence pool spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a \f[I]pool set\f[] may be stored on a different memory device or pmem\-aware filesystem. .PP Creation of all the parts of the pool set can be done with \f[B]pmemcto_create\f[](); however, the recommended method for creating pool sets is by using the \f[B]pmempool\f[](1) utility. .PP When creating a pool set consisting of multiple files, the \f[I]path\f[] argument passed to \f[B]pmemcto_create\f[]() must point to the special \f[I]set\f[] file that defines the pool layout and the location of all the parts of the pool set. The \f[I]poolsize\f[] argument must be 0. The meaning of the \f[I]layout\f[] and \f[I]mode\f[] arguments does not change, except that the same \f[I]mode\f[] is used for creation of all the parts of the pool set. .PP For more information on pool set format, see \f[B]poolset\f[](5). .PP The \f[B]pmemcto_open\f[]() function opens an existing close\-to\-open persistence memory pool. \f[I]path\f[] must be an existing file containing a pmemcto memory pool as created by \f[B]pmemcto_create\f[](). If \f[I]layout\f[] is non\-NULL, it is compared to the layout name provided to \f[B]pmemcto_create\f[]() when the pool was first created. This can be used to verify that the layout of the pool matches what was expected. The application must have permission to open the file and memory map it with read/write permissions. .PP The \f[B]pmemcto_close\f[]() function closes the memory pool indicated by \f[I]pcp\f[] and deletes the memory pool handle. The close\-to\-open memory pool itself lives on in the file that contains it and may be re\-opened at a later time using \f[B]pmemcto_open\f[]() as described above. If the pool was not closed gracefully due to abnormal program termination or power failure, the pool is in an inconsistent state causing subsequent pool opening to fail. .PP The \f[B]pmemcto_check\f[]() function performs a consistency check of the file indicated by \f[I]path\f[], and returns 1 if the memory pool is found to be consistent. If the pool is found not to be consistent, further use of the file with \f[B]libpmemcto\f[](7) will result in undefined behavior. The debug version of \f[B]libpmemcto\f[](7) will provide additional details on inconsistencies when \f[B]PMEMCTO_LOG_LEVEL\f[] is at least 1, as described in the \f[B]DEBUGGING AND ERROR HANDLING\f[] section of \f[B]libpmemcto\f[](7). \f[B]pmemcto_check\f[]() will return \-1 and set \f[I]errno\f[] if it cannot perform the consistency check due to other errors. \f[B]pmemcto_check\f[]() opens the given \f[I]path\f[] read\-only so it never makes any changes to the file. This function is not supported on Device DAX. .SH RETURN VALUE .PP On success, \f[B]pmemcto_create\f[]() returns a \f[I]PMEMctopool*\f[] handle to the close\-to\-open persistence memory pool. On error, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]pmemcto_open\f[]() returns a \f[I]PMEMctopool*\f[] handle that can be used with most of the functions in \f[B]libpmemcto\f[](7). On error, it returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]pmemcto_close\f[]() function returns no value. .PP \f[B]pmemcto_check\f[]() returns 1 if the memory pool is found to be consistent. If the check is successfully performed but the pool is found to be inconsistent, \f[B]pmemcto_check\f[]() returns 0. If the consistency check cannot be performed, \f[B]pmemcto_check\f[]() returns \-1 and sets \f[I]errno\f[] appropriately. This includes the case where \f[I]layout\f[] is non\-NULL and does not match the layout string given when the pool was created. .SH ERRORS .PP \f[B]EINVAL\f[] \[lq]layout\[rq] string does not match the layout stored in pool header. .PP \f[B]EINVAL\f[] \[lq]layout\[rq] string is longer than \f[B]PMEMCTO_MAX_LAYOUT\f[]. .PP \f[B]EINVAL\f[] \f[I]poolsize\f[] is less than \f[B]PMEMCTO_MIN_POOL\f[]. .PP \f[B]EINVAL\f[] Invalid format of the pool set file. .PP \f[B]EINVAL\f[] Invalid pool header. .PP \f[B]EEXIST\f[] \f[I]path\f[] passed to \f[B]pmemcto_create\f[]() points to a pool set file, but \f[I]poolsize\f[] is not zero. .PP \f[B]EEXIST\f[] \f[I]path\f[] passed to \f[B]pmemcto_create\f[]() points to an existing file, but \f[I]poolsize\f[] is not zero. .PP \f[B]EEXIST\f[] \f[I]path\f[] passed to \f[B]pmemcto_create\f[]() points to an existing file, which is not\-empty. .PP \f[B]EAGAIN\f[] The pmemcto pool pointed by \f[I]path\f[] is already open. .PP \f[B]EACCES\f[] No write access permission to the pool file(s). .PP \f[B]ENOMEM\f[] The pool cannot be mapped at the address it was created. .SH CAVEATS .PP Not all file systems support \f[B]posix_fallocate\f[](3). \f[B]pmemcto_create\f[]() will fail if the underlying file system does not support \f[B]posix_fallocate\f[](3). .SH BUGS .PP Unlike \f[B]libpmemobj\f[](7), data replication is not supported in \f[B]libpmemcto\f[](7). Thus, it is not allowed to specify replica sections in pool set files. .SH SEE ALSO .PP \f[B]ndctl\-create\-namespace\f[](1), \f[B]pmempool\-create\f[](1), \f[B]jemalloc\f[](3), \f[B]poolset\f[](5), \f[B]libpmemcto\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_realloc.3000066400000000000000000000000251331545616200204070ustar00rootroot00000000000000.so pmemcto_malloc.3 pmdk-1.4.1/doc/generated/pmemcto_set_funcs.3000066400000000000000000000000261331545616200207600ustar00rootroot00000000000000.so man7/libpmemcto.7 pmdk-1.4.1/doc/generated/pmemcto_set_root_pointer.3000066400000000000000000000063651331545616200224010ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_SET_ROOT_POINTER" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_set_root_pointer, pmemcto_get_root_pointer \[en] set or obtain the root object pointer .SH SYNOPSIS .IP .nf \f[C] #include\ void\ pmemcto_set_root_pointer(PMEMctopool\ *pcp,\ void\ *ptr); void\ *pmemcto_get_root_pointer(PMEMctopool\ *pcp); \f[] .fi .SH DESCRIPTION .PP The root object of persistent memory pool is an entry point for all other persistent objects allocated using the \f[B]libpmemcto\f[](7) APIs. In other words, every single object stored in persistent memory pool should have the root object at the end of its reference path. There is exactly one root object in each pool. .PP The \f[B]pmemcto_set_root_pointer\f[]() function saves the pointer to the root object in given pool. The \f[I]ptr\f[] must have been returned by a previous call to \f[B]pmemcto_malloc\f[](3), \f[B]pmemcto_calloc\f[](3), \f[B]pmemcto_realloc\f[](3) or \f[B]pmemcto_aligned_alloc\f[](3) for \f[I]the same pool of memory\f[]. .PP The \f[B]pmemcto_get_root_pointer\f[]() function returns the pointer to the root object in given pool, or NULL if the root pointer was never set. .SH RETURN VALUE .PP The \f[B]pmemcto_set_root_pointer\f[]() function returns no value. .PP The \f[B]pmemcto_get_root_pointer\f[]() function returns the pointer to the root object in given pool, or NULL if the root pointer was never set. .SH SEE ALSO .PP \f[B]pmemcto_aligned_alloc\f[](3), \f[B]pmemcto_calloc\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]pmemcto_realloc\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_stats_print.3000066400000000000000000000063441331545616200213520ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_STATS_PRINT" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_stats_print \[en] write human\-readable memory pool statistics .SH SYNOPSIS .IP .nf \f[C] #include\ void\ pmemcto_stats_print(PMEMctopool\ *pcp,\ const\ char\ *opts); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_stats_print\f[]() function produces messages containing statistics about the given memory pool. The output is printed using \f[B]libpmemcto\f[](7) internal \f[I]print_func\f[] function (see \f[B]pmemcto_set_funcs\f[](3)). That means the output typically appears on \f[I]stderr\f[] unless the caller supplies a replacement \f[I]print_func\f[] or sets the environment variable \f[B]PMEMCTO_LOG_FILE\f[] to direct output elsewhere. The \f[I]opts\f[] string can either be NULL or it can contain a list of options that change the stats printed. General information that never changes during execution can be omitted by specifying \[lq]g\[rq] as a character within the opts string. The characters \[lq]m\[rq] and \[lq]a\[rq] can be specified to omit merged arena and per arena statistics, respectively; \[lq]b\[rq] and \[lq]l\[rq] can be specified to omit per size class statistics for bins and large objects, respectively. Unrecognized characters are silently ignored. Note that thread caching may prevent some statistics from being completely up to date. See \f[B]jemalloc\f[](3) for more detail (the description of the available \f[I]opts\f[] above was taken from that man page). .SH SEE ALSO .PP \f[B]jemalloc\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_strdup.3000066400000000000000000000056311331545616200203170ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_STRDUP" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_strdup \[en] duplicate a string .SH SYNOPSIS .IP .nf \f[C] #include\ char\ *pmemcto_strdup(PMEMctopool\ *pcp,\ const\ char\ *s); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_strdup\f[]() function provides the same semantics as \f[B]strdup\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It returns a pointer to a new string which is a duplicate of the string \f[I]s\f[]. Memory for the new string is obtained with \f[B]pmemcto_malloc\f[](3), on the given memory pool, and can be freed with \f[B]pmemcto_free\f[](3) on the same memory pool. .SH RETURN VALUE .PP On success, the \f[B]pmemcto_strdup\f[]() function returns a pointer to the duplicated string. If \f[B]pmemcto_strdup\f[]() is unable to satisfy the allocation request, a NULL pointer is returned and \f[I]errno\f[] is set appropriately. .SH ERRORS .PP \f[B]ENOMEM\f[] Insufficient memory available to allocate duplicated string. .SH SEE ALSO .PP \f[B]jemalloc\f[](3), \f[B]malloc\f[](3), \f[B]strdup\f[](3), \f[B]wcsdup\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]pmemcto_wcsdup\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemcto_wcsdup.3000066400000000000000000000056651331545616200203120ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMCTO_WCSDUP" "3" "2018-05-21" "PMDK - libpmemcto API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP pmemcto_wcsdup \[en] duplicate a wide\-char string .SH SYNOPSIS .IP .nf \f[C] #include\ wchar_t\ *pmemcto_wcsdup(PMEMctopool\ *pcp,\ const\ wchar_t\ *s); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemcto_wcsdup\f[]() function provides the same semantics as \f[B]wcsdup\f[](3), but operates on the memory pool \f[I]pcp\f[] instead of the process heap supplied by the system. It returns a pointer to a new wide\-char string which is a duplicate of the string \f[I]s\f[]. Memory for the new string is obtained with \f[B]pmemcto_malloc\f[](3), on the given memory pool, and can be freed with \f[B]pmemcto_free\f[](3) on the same memory pool. .SH RETURN VALUE .PP On success, the \f[B]pmemcto_wcsdup\f[]() function returns a pointer to the duplicated string. If \f[B]pmemcto_wcsdup\f[]() is unable to satisfy the allocation request, a NULL pointer is returned and \f[I]errno\f[] is set appropriately. .SH ERRORS .PP \f[B]ENOMEM\f[] Insufficient memory available to allocate duplicated string. .SH SEE ALSO .PP \f[B]jemalloc\f[](3), \f[B]malloc\f[](3), \f[B]strdup\f[](3), \f[B]wcsdup\f[](3), \f[B]pmemcto_malloc\f[](3), \f[B]pmemcto_strdup\f[](3), \f[B]libpmemcto\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemlog_append.3000066400000000000000000000067701331545616200202460ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMLOG_APPEND" "3" "2018-05-21" "PMDK - pmemlog API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemlog_append\f[](), \f[B]pmemlog_appendv\f[]() \[en] append bytes to the persistent memory resident log file .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmemlog_append(PMEMlogpool\ *plp,\ const\ void\ *buf,\ size_t\ count); int\ pmemlog_appendv(PMEMlogpool\ *plp,\ const\ struct\ iovec\ *iov,\ int\ iovcnt); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemlog_append\f[]() function appends \f[I]count\f[] bytes from \f[I]buf\f[] to the current write offset in the log memory pool \f[I]plp\f[]. Calling this function is analogous to appending to a file. The append is atomic and cannot be torn by a program failure or system crash. .PP The \f[B]pmemlog_appendv\f[]() function appends to the log memory pool \f[I]plp\f[] from the scatter/gather list \f[I]iov\f[] in a manner similar to \f[B]writev\f[](2). The entire list of buffers is appended atomically, as if the buffers in \f[I]iov\f[] were concatenated in order. The append is atomic and cannot be torn by a program failure or system crash. .SH RETURN VALUE .PP On success, \f[B]pmemlog_append\f[]() and \f[B]pmemlog_appendv\f[]() return 0. On error, they return \-1 and set \f[I]errno\f[] appropriately. .SH ERRORS .PP \f[B]EINVAL\f[] The vector count \f[I]iovcnt\f[] is less than zero. .PP \f[B]ENOSPC\f[] There is no room for the data in the log file. .PP \f[B]EROFS\f[] The log file is open in read\-only mode. .SH NOTES .PP Since \f[B]libpmemlog\f[](3) is designed as a low\-latency code path, many of the checks routinely done by the operating system for \f[B]writev\f[](2) are not practical in the library's implementation of \f[B]pmemlog_appendv\f[](). No attempt is made to detect NULL or incorrect pointers, for example. .SH SEE ALSO .PP \f[B]writev\f[](2), \f[B]libpmemlog\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemlog_appendv.3000066400000000000000000000000251331545616200204170ustar00rootroot00000000000000.so pmemlog_append.3 pmdk-1.4.1/doc/generated/pmemlog_check.3000066400000000000000000000000251331545616200200370ustar00rootroot00000000000000.so pmemlog_create.3 pmdk-1.4.1/doc/generated/pmemlog_check_version.3000066400000000000000000000000261331545616200216050ustar00rootroot00000000000000.so man7/libpmemlog.7 pmdk-1.4.1/doc/generated/pmemlog_close.3000066400000000000000000000000251331545616200200670ustar00rootroot00000000000000.so pmemlog_create.3 pmdk-1.4.1/doc/generated/pmemlog_create.3000066400000000000000000000164701331545616200202400ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMLOG_CREATE" "3" "2018-05-21" "PMDK - pmemlog API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemlog_create\f[](), \f[B]pmemlog_open\f[](), \f[B]pmemlog_close\f[](), \f[B]pmemlog_check\f[]() \[en] create, open, close and validate persistent memory resident log file .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMlogpool\ *pmemlog_open(const\ char\ *path); PMEMlogpool\ *pmemlog_create(const\ char\ *path,\ size_t\ poolsize,\ mode_t\ mode); void\ pmemlog_close(PMEMlogpool\ *plp); int\ pmemlog_check(const\ char\ *path); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemlog_create\f[]() function creates a log memory pool with the given total \f[I]poolsize\f[]. Since the transactional nature of a log memory pool requires some space overhead in the memory pool, the resulting available log size is less than \f[I]poolsize\f[], and is made available to the caller via the \f[B]pmemlog_nbyte\f[](3) function. \f[I]path\f[] specifies the name of the memory pool file to be created. \f[I]mode\f[] specifies the permissions to use when creating the file as described by \f[B]creat\f[](2). The memory pool file is fully allocated to the size \f[I]poolsize\f[] using \f[B]posix_fallocate\f[](3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling \f[B]pmemlog_create\f[]() and then specifying \f[I]poolsize\f[] as zero. In this case \f[B]pmemlog_create\f[]() will take the pool size from the size of the existing file and will verify that the file appears to be empty by searching for any non\-zero data in the pool header at the beginning of the file. The net pool size of a pool file is equal to the file size. The minimum net pool size allowed by the library for a log pool is defined in \f[B]\f[] as \f[B]PMEMLOG_MIN_POOL\f[]. .PP Depending on the configuration of the system, the available non\-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemlog memory pool could be limited by the capacity of a single memory device. \f[B]libpmemlog\f[](7) allows building persistent memory resident logs spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a \f[I]pool set\f[] may be stored on a different memory device or pmem\-aware filesystem. .PP Creation of all the parts of the pool set can be done with \f[B]pmemlog_create\f[](); however, the recommended method for creating pool sets is with the \f[B]pmempool\f[](1) utility. .PP When creating a pool set consisting of multiple files, the \f[I]path\f[] argument passed to \f[B]pmemlog_create\f[]() must point to the special \f[I]set\f[] file that defines the pool layout and the location of all the parts of the pool set. The \f[I]poolsize\f[] argument must be 0. The meaning of the \f[I]mode\f[] argument does not change, except that the same \f[I]mode\f[] is used for creation of all the parts of the pool set. .PP The set file is a plain text file, the structure of which is described in \f[B]poolset\f[](5). .PP The \f[B]pmemlog_open\f[]() function opens an existing log memory pool. Similar to \f[B]pmemlog_create\f[](), \f[I]path\f[] must identify either an existing log memory pool file, or the \f[I]set\f[] file used to create a pool set. The application must have permission to open the file and memory map the file or pool set with read/write permissions. .PP The \f[B]pmemlog_close\f[]() function closes the memory pool indicated by \f[I]plp\f[] and deletes the memory pool handle. The log memory pool itself lives on in the file that contains it and may be re\-opened at a later time using \f[B]pmemlog_open\f[]() as described above. .PP The \f[B]pmemlog_check\f[]() function performs a consistency check of the file indicated by \f[I]path\f[]. \f[B]pmemlog_check\f[]() opens the given \f[I]path\f[] read\-only so it never makes any changes to the file. This function is not supported on Device DAX. .SH RETURN VALUE .PP On success, \f[B]pmemlog_create\f[]() returns a \f[I]PMEMlogpool*\f[] handle to the memory pool that is used with most of the functions from \f[B]libpmemlog\f[](7). If an error prevents any of the pool set files from being created, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]pmemlog_open\f[]() returns a \f[I]PMEMlogpool*\f[] handle to the memory pool that is used with most of the functions from \f[B]libpmemlog\f[](7). If an error prevents the pool from being opened, or a pool set is being opened and the actual size of any file does not match the corresponding part size defined in the \f[I]set\f[] file, \f[B]pmemlog_open\f[]() returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]pmemlog_close\f[]() function returns no value. .PP The \f[B]pmemlog_check\f[]() function returns 1 if the persistent memory resident log file is found to be consistent. Any inconsistencies will cause \f[B]pmemlog_check\f[]() to return 0, in which case the use of the file with \f[B]libpmemlog\f[] will result in undefined behavior. The debug version of \f[B]libpmemlog\f[] will provide additional details on inconsistencies when \f[B]PMEMLOG_LOG_LEVEL\f[] is at least 1, as described in the \f[B]DEBUGGING AND ERROR HANDLING\f[] section in \f[B]libpmemlog\f[](7). \f[B]pmemlog_check\f[]() will return \-1 and set \f[I]errno\f[] if it cannot perform the consistency check due to other errors. .SH CAVEATS .PP Not all file systems support \f[B]posix_fallocate\f[](3). \f[B]pmemlog_create\f[]() will fail if the underlying file system does not support \f[B]posix_fallocate\f[](3). .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]creat\f[](2), \f[B]posix_fallocate\f[](3), \f[B]pmemlog_nbyte\f[](3), \f[B]poolset\f[](5), \f[B]libpmemlog\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemlog_errormsg.3000066400000000000000000000000261331545616200206230ustar00rootroot00000000000000.so man7/libpmemlog.7 pmdk-1.4.1/doc/generated/pmemlog_nbyte.3000066400000000000000000000046001331545616200201060ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMLOG_NBYTE" "3" "2018-05-21" "PMDK - pmemlog API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemlog_nbyte\f[]() \[en] checks the amount of usable space in the log pool. .SH SYNOPSIS .IP .nf \f[C] #include\ size_t\ pmemlog_nbyte(PMEMlogpool\ *plp); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemlog_nbyte\f[]() function checks the amount of usable space in the log \f[I]plp\f[]. This function may be used on a log to determine how much usable space is available after \f[B]libpmemlog\f[](7) has added its metadata to the memory pool. .SH RETURN VALUE .PP The \f[B]pmemlog_nbyte\f[]() function returns the amount of usable space in the log \f[I]plp\f[]. .SH SEE ALSO .PP \f[B]libpmemlog\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemlog_open.3000066400000000000000000000000251331545616200177230ustar00rootroot00000000000000.so pmemlog_create.3 pmdk-1.4.1/doc/generated/pmemlog_rewind.3000066400000000000000000000000231331545616200202500ustar00rootroot00000000000000.so pmemlog_tell.3 pmdk-1.4.1/doc/generated/pmemlog_set_funcs.3000066400000000000000000000000261331545616200207540ustar00rootroot00000000000000.so man7/libpmemlog.7 pmdk-1.4.1/doc/generated/pmemlog_tell.3000066400000000000000000000077021331545616200177330ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMLOG_TELL" "3" "2018-05-21" "PMDK - pmemlog API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemlog_tell\f[](), \f[B]pmemlog_rewind\f[](), \f[B]pmemlog_walk\f[]() \[en] checks current write point for the log or walks through the log .SH SYNOPSIS .IP .nf \f[C] #include\ long\ long\ pmemlog_tell(PMEMlogpool\ *plp); void\ pmemlog_rewind(PMEMlogpool\ *plp); void\ pmemlog_walk(PMEMlogpool\ *plp,\ size_t\ chunksize, \ \ \ \ int\ (*process_chunk)(const\ void\ *buf,\ size_t\ len,\ void\ *arg), \ \ \ \ void\ *arg); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemlog_tell\f[]() function returns the current write point for the log, expressed as a byte offset into the usable log space in the memory pool. This offset starts off as zero on a newly\-created log, and is incremented by each successful append operation. This function can be used to determine how much data is currently in the log. .PP The \f[B]pmemlog_rewind\f[]() function resets the current write point for the log to zero. After this call, the next append adds to the beginning of the log. .PP The \f[B]pmemlog_walk\f[]() function walks through the log \f[I]plp\f[], from beginning to end, calling the callback function \f[I]process_chunk\f[] for each \f[I]chunksize\f[] block of data found. The argument \f[I]arg\f[] is also passed to the callback to help avoid the need for global state. The \f[I]chunksize\f[] argument is useful for logs with fixed\-length records and may be specified as 0 to cause a single call to the callback with the entire log contents passed as the \f[I]buf\f[] argument. The \f[I]len\f[] argument tells the \f[I]process_chunk\f[] function how much data \f[I]buf\f[] is holding. The callback function should return 1 if \f[B]pmemlog_walk\f[]() should continue walking through the log, or 0 to terminate the walk. The callback function is called while holding \f[B]libpmemlog\f[](7) internal locks that make calls atomic, so the callback function must not try to append to the log itself or deadlock will occur. .SH RETURN VALUE .PP On success, \f[B]pmemlog_tell\f[]() returns the current write point for the log. On error, it returns \-1 and sets \f[I]errno\f[] appropriately. .PP The \f[B]pmemlog_rewind\f[]() and \f[B]pmemlog_walk\f[]() functions return no value. .SH SEE ALSO .PP \f[B]libpmemlog\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemlog_walk.3000066400000000000000000000000231331545616200177160ustar00rootroot00000000000000.so pmemlog_tell.3 pmdk-1.4.1/doc/generated/pmemobj_action.3000066400000000000000000000174601331545616200202430ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_ACTION" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_reserve\f[](), \f[B]pmemobj_xreserve\f[](), \f[B]pmemobj_set_value\f[](), \f[B]pmemobj_publish\f[](), \f[B]pmemobj_tx_publish\f[](), \f[B]pmemobj_cancel\f[](), \f[B]POBJ_RESERVE_NEW\f[](), \f[B]POBJ_RESERVE_ALLOC\f[]() \[en] Delayed atomicity actions (EXPERIMENTAL) .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMoid\ pmemobj_reserve(PMEMobjpool\ *pop,\ struct\ pobj_action\ *act, \ \ \ \ size_t\ size,\ uint64_t\ type_num);\ (EXPERIMENTAL) PMEMoid\ pmemobj_xreserve(PMEMobjpool\ *pop,\ struct\ pobj_action\ *act, \ \ \ \ size_t\ size,\ uint64_t\ type_num,\ uint64_t\ flags);\ (EXPERIMENTAL) void\ pmemobj_set_value(PMEMobjpool\ *pop,\ struct\ pobj_action\ *act, \ \ \ \ uint64_t\ *ptr,\ uint64_t\ value);\ (EXPERIMENTAL) void\ pmemobj_publish(PMEMobjpool\ *pop,\ struct\ pobj_action\ *actv, \ \ \ \ size_t\ actvcnt);\ (EXPERIMENTAL) int\ pmemobj_tx_publish(struct\ pobj_action\ *actv,\ size_t\ actvcnt);\ (EXPERIMENTAL) pmemobj_cancel(PMEMobjpool\ *pop,\ struct\ pobj_action\ *actv, \ \ \ \ size_t\ actvcnt);\ (EXPERIMENTAL) POBJ_RESERVE_NEW(pop,\ t,\ act)\ (EXPERIMENTAL) POBJ_RESERVE_ALLOC(pop,\ t,\ size,\ act)\ (EXPERIMENTAL) \f[] .fi .SH DESCRIPTION .PP All of the functions described so far have an immediate effect on the persistent state of the pool, and as such, the cost of maintaining fail\-safety is paid outright and, most importantly, in the calling thread. This behavior makes implementing algorithms involving relaxed consistency guarantees difficult, if not outright impossible. .PP The following set of functions introduce a mechanism that allows one to delay the persistent publication of a set of prepared actions to an arbitrary moment in time of the execution of a program. .PP The publication is fail\-safe atomic in the scope of the entire collection of actions, but the number of said actions is limited by \f[I]POBJ_MAX_ACTIONS\f[] constant. If a program exists without publishing the actions, or the actions are canceled, any resources reserved by those actions are released and placed back in the pool. .PP A single action is represented by a single \f[C]struct\ pobj_action\f[]. Functions that create actions take that structure by pointer, whereas functions that publish actions take array of actions and the size of the array. The actions can be created, and published, from different threads. When creating actions, the \f[I]act\f[] argument must be non\-NULL and point to a \f[C]struct\ pobj_action\f[], the structure will be populated by the function and must not be modified or deallocated until after publishing. .PP The \f[B]pmemobj_reserve\f[]() functions performs a transient reservation of an object. Behaves similarly to \f[B]pmemobj_alloc\f[](3), but performs no modification to the persistent state. The object returned by this function can be freely modified without worrying about fail\-safe atomicity until the object has been published. Any modifications of the object must be manually persisted, just like in the case of the atomic API. .PP \f[B]pmemobj_xreserve\f[]() is equivalent to \f[B]pmemobj_reserve\f[](), but with an additional \f[I]flags\f[] argument that is a bitmask of the following values: .IP \[bu] 2 \f[B]POBJ_XALLOC_ZERO\f[] \- zero the object .IP \[bu] 2 \f[B]POBJ_CLASS_ID(class_id)\f[] \- allocate the object from allocation class \f[I]class_id\f[]. The class id cannot be 0. .PP The \f[B]pmemobj_set_value\f[] function prepares an action that, once published, will modify the memory location pointed to by \f[I]ptr\f[] to \f[I]value\f[]. .PP The \f[B]pmemobj_publish\f[] function publishes the provided set of actions. The publication is fail\-safe atomic. Once done, the persistent state will reflect the changes contained in the actions. The \f[I]actvcnt\f[] cannot exceed \f[I]POBJ_MAX_ACTIONS\f[]. .PP The \f[B]pmemobj_tx_publish\f[] function moves the provided actions to the scope of the transaction in which it is called. Only object reservations are supported in transactional publish. Once done, the reserved objects will follow normal transactional semantics. Can only be called during \f[I]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_cancel\f[] function releases any resources held by the provided set of actions and invalidates all actions. .PP The \f[B]POBJ_RESERVE_NEW\f[] macro is a typed variant of \f[B]pmemobj_reserve\f[]. The size of the reservation is determined from the provided type \f[I]t\f[]. .PP The \f[B]POBJ_RESERVE_ALLOC\f[] macro is a typed variant of \f[B]pmemobj_reserve\f[]. The \f[I]size\f[] of the reservation is user\-provided. .SH EXAMPLES .PP The following code shows atomic append of two objects into a singly linked list. .IP .nf \f[C] struct\ list_node\ { \ \ \ \ int\ value; \ \ \ \ PMEMoid\ next; }; /*\ statically\ allocate\ the\ array\ of\ actions\ */ struct\ pobj_action\ actv[4]; /*\ reserve,\ populate\ and\ persist\ the\ first\ object\ */ PMEMoid\ tail\ =\ pmemobj_reserve(pop,\ &actv[0],\ sizeof(struct\ list_node),\ 0); if\ (TOID_IS_NULL(tail)) \ \ \ \ return\ \-1; D_RW(tail)\->value\ =\ 1; D_RW(tail)\->next\ =\ OID_NULL; pmemobj_persist(pop,\ D_RW(tail),\ sizeof(struct\ list_node)); /*\ reserve,\ populate\ and\ persist\ the\ second\ object\ */ PMEMoid\ head\ =\ pmemobj_reserve(pop,\ &actv[1],\ sizeof(struct\ list_node),\ 0); if\ (TOID_IS_NULL(head)) \ \ \ \ return\ \-1; D_RW(head)\->value\ =\ 2; D_RW(head)\->next\ =\ tail; pmemobj_persist(pop,\ D_RW(head),\ sizeof(struct\ list_node)); /*\ create\ actions\ to\ set\ the\ PMEMoid\ to\ the\ new\ values\ */ pmemobj_set_value(pop,\ &actv[2],\ &D_RO(root)\->head.pool_uuid_lo,\ head.pool_uuid_lo); pmemobj_set_value(pop,\ &actv[3],\ &D_RO(root)\->head.off,\ head.off); /*\ atomically\ publish\ the\ above\ actions\ */ pmemobj_publish(pop,\ actv,\ 4); \f[] .fi .SH RETURN VALUE .PP On success, \f[B]pmemobj_reserve\f[]() functions return a handle to the newly reserved object, otherwise an \f[I]OID_NULL\f[] is returned. .PP On success, \f[B]pmemobj_tx_publish\f[]() returns 0, otherwise, stage changes to \f[I]TX_STAGE_ONABORT\f[] and \f[I]errno\f[] is set appropriately .SH SEE ALSO .PP \f[B]pmemobj_alloc\f[](3), \f[B]pmemobj_tx_alloc\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_alloc.3000066400000000000000000000355261331545616200200630ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_ALLOC" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_alloc\f[](), \f[B]pmemobj_xalloc\f[](), \f[B]pmemobj_zalloc\f[](), \f[B]pmemobj_realloc\f[](), \f[B]pmemobj_zrealloc\f[](), \f[B]pmemobj_strdup\f[](), \f[B]pmemobj_wcsdup\f[](), \f[B]pmemobj_alloc_usable_size\f[](), \f[B]POBJ_NEW\f[](), \f[B]POBJ_ALLOC\f[](), \f[B]POBJ_ZNEW\f[](), \f[B]POBJ_ZALLOC\f[](), \f[B]POBJ_REALLOC\f[](), \f[B]POBJ_ZREALLOC\f[](), \f[B]POBJ_FREE\f[]() \[en] non\-transactional atomic allocations .SH SYNOPSIS .IP .nf \f[C] #include\ typedef\ int\ (*pmemobj_constr)(**PMEMobjpool\ *pop,\ void\ *ptr,\ void\ *arg); int\ pmemobj_alloc(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ size_t\ size, \ \ \ \ uint64_t\ type_num,\ pmemobj_constr\ constructor,\ void\ *arg); int\ pmemobj_xalloc(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ size_t\ size, \ \ \ \ uint64_t\ type_num,\ uint64_t\ flags,\ pmemobj_constr\ constructor, \ \ \ \ void\ *arg);\ (EXPERIMENTAL) int\ pmemobj_zalloc(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ size_t\ size, \ \ \ \ uint64_t\ type_num); void\ pmemobj_free(PMEMoid\ *oidp); int\ pmemobj_realloc(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ size_t\ size, \ \ \ \ uint64_t\ type_num); int\ pmemobj_zrealloc(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ size_t\ size, \ \ \ \ uint64_t\ type_num); int\ pmemobj_strdup(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ const\ char\ *s, \ \ \ \ uint64_t\ type_num); int\ pmemobj_wcsdup(PMEMobjpool\ *pop,\ PMEMoid\ *oidp,\ const\ wchar_t\ *s, \ \ \ \ uint64_t\ type_num); size_t\ pmemobj_alloc_usable_size(PMEMoid\ oid); POBJ_NEW(PMEMobjpool\ *pop,\ TOID\ *oidp,\ TYPE,\ pmemobj_constr\ constructor, \ \ \ \ void\ *arg) POBJ_ALLOC(PMEMobjpool\ *pop,\ TOID\ *oidp,\ TYPE,\ size_t\ size, \ \ \ \ pmemobj_constr\ constructor,\ void\ *arg) POBJ_ZNEW(PMEMobjpool\ *pop,\ TOID\ *oidp,\ TYPE) POBJ_ZALLOC(PMEMobjpool\ *pop,\ TOID\ *oidp,\ TYPE,\ size_t\ size) POBJ_REALLOC(PMEMobjpool\ *pop,\ TOID\ *oidp,\ TYPE,\ size_t\ size) POBJ_ZREALLOC(PMEMobjpool\ *pop,\ TOID\ *oidp,\ TYPE,\ size_t\ size) POBJ_FREE(TOID\ *oidp) \f[] .fi .SH DESCRIPTION .PP Functions described in this document provide the mechanism to allocate, resize and free objects from the persistent memory pool in a thread\-safe and fail\-safe manner. All the routines are atomic with respect to other threads and any power\-fail interruptions. If any of these operations is torn by program failure or system crash, on recovery they are guaranteed to be entirely completed or discarded, leaving the persistent memory heap and internal object containers in a consistent state. .PP All these functions can be used outside transactions. Note that operations performed using the non\-transactional API are considered durable after completion, even if executed within an open transaction. Such non\-transactional changes will not be rolled back if the transaction is aborted or interrupted. .PP The allocations are always aligned to a cache\-line boundary. .PP The \f[I]pmemobj_constr\f[] type represents a constructor for atomic allocation from the persistent memory heap associated with memory pool \f[I]pop\f[]. \f[I]ptr\f[] is a pointer to the allocated memory area and \f[I]arg\f[] is a user\-defined argument passed to the constructor. .PP The \f[B]pmemobj_alloc\f[]() function allocates a new object from the persistent memory heap associated with memory pool \f[I]pop\f[]. The \f[I]PMEMoid\f[] of the allocated object is stored in \f[I]oidp\f[]. If \f[I]oidp\f[] is NULL, then the newly allocated object may be accessed only by iterating objects in the object container associated with the type number \f[I]type_num\f[], as described in \f[B]POBJ_FOREACH\f[](3). If \f[I]oidp\f[] points to a memory location from the \f[B]pmemobj\f[] heap, \f[I]oidp\f[] is modified atomically. Before returning, \f[B]pmemobj_alloc\f[]() calls the \f[I]constructor\f[] function, passing the pool handle \f[I]pop\f[], the pointer to the newly allocated object in \f[I]ptr\f[], and the \f[I]arg\f[] argument. It is guaranteed that the allocated object is either properly initialized, or if the allocation is interrupted before the constructor completes, the memory space reserved for the object is reclaimed. \f[I]size\f[] can be any non\-zero value; however, due to internal padding and object metadata, the actual size of the allocation will differ from the requested size by at least 64 bytes. For this reason, making allocations of a size less than 64 bytes is extremely inefficient and discouraged. The allocated object is added to the internal container associated with \f[I]type_num\f[]. .PP \f[B]pmemobj_xalloc\f[]() is equivalent to \f[B]pmemobj_alloc\f[](), but with an additional \f[I]flags\f[] argument that is a bitmask of the following values: .IP \[bu] 2 \f[B]POBJ_XALLOC_ZERO\f[] \- zero the object (equivalent of \f[B]pmemobj_zalloc\f[]()) .IP \[bu] 2 \f[B]POBJ_CLASS_ID(class_id)\f[] \- allocate the object from allocation class \f[I]class_id\f[]. The class id cannot be 0. .PP The \f[B]pmemobj_zalloc\f[]() function allocates a new zeroed object from the persistent memory heap associated with memory pool \f[I]pop\f[]. The \f[I]PMEMoid\f[] of the allocated object is stored in \f[I]oidp\f[]. If \f[I]oidp\f[] is NULL, then the newly allocated object may be accessed only by iterating objects in the object container associated with the type number \f[I]type_num\f[], as described in \f[B]POBJ_FOREACH\f[](3). If \f[I]oidp\f[] points to a memory location from the \f[B]pmemobj\f[] heap, \f[I]oidp\f[] is modified atomically. \f[I]size\f[] can be any non\-zero value; however, due to internal padding and object metadata, the actual size of the allocation will differ from the requested one by at least 64 bytes. For this reason, making allocations of a size less than 64 bytes is extremely inefficient and discouraged. The allocated object is added to the internal container associated with \f[I]type_num\f[]. .PP The \f[B]pmemobj_free\f[]() function frees the memory space represented by \f[I]oidp\f[], which must have been allocated by a previous call to \f[B]pmemobj_alloc\f[](), \f[B]pmemobj_xalloc\f[](), \f[B]pmemobj_zalloc\f[](), \f[B]pmemobj_realloc\f[](), or \f[B]pmemobj_zrealloc\f[](). \f[B]pmemobj_free\f[]() provides the same semantics as \f[B]free\f[](3), but instead of operating on the process heap supplied by the system, it operates on the persistent memory heap. If \f[I]oidp\f[] is \f[B]OID_NULL\f[], no operation is performed. If \f[I]oidp\f[] is NULL or if it points to the root object's \f[I]OID\f[], the behavior of \f[B]pmemobj_free\f[]() is undefined. \f[I]oidp\f[] is set to \f[B]OID_NULL\f[] after the memory is freed. If \f[I]oidp\f[] points to a memory location from the \f[B]pmemobj\f[] heap, \f[I]oidp\f[] is modified atomically. .PP The \f[B]pmemobj_realloc\f[]() function changes the size of the object represented by \f[I]oidp\f[] to \f[I]size\f[] bytes. \f[B]pmemobj_realloc\f[]() provides similar semantics to \f[B]realloc\f[](3), but operates on the persistent memory heap associated with memory pool \f[I]pop\f[]. The resized object is also added or moved to the internal container associated with type number \f[I]type_num\f[]. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will \f[I]not\f[] be initialized. If \f[I]oidp\f[] is \f[I]OID_NULL\f[], then the call is equivalent to \f[I]pmemobj_alloc(pop, size, type_num)\f[]. If \f[I]size\f[] is equal to zero, and \f[I]oidp\f[] is not \f[B]OID_NULL\f[], then the call is equivalent to \f[I]pmemobj_free(oid)\f[]. Unless \f[I]oidp\f[] is \f[B]OID_NULL\f[], it must have been allocated by an earlier call to \f[B]pmemobj_alloc\f[](), \f[B]pmemobj_xalloc\f[](), \f[B]pmemobj_zalloc\f[](), \f[B]pmemobj_realloc\f[](), or \f[B]pmemobj_zrealloc\f[](). Note that the object handle value may change as a result of reallocation. If the object was moved, the memory space represented by \f[I]oid\f[] is reclaimed. If \f[I]oidp\f[] points to a memory location from the \f[B]pmemobj\f[] heap, \f[I]oidp\f[] is modified atomically. If \f[I]oidp\f[] is NULL or if it points to the root object's \f[I]OID\f[], the behavior of \f[B]pmemobj_realloc\f[]() is undefined. .PP \f[B]pmemobj_zrealloc\f[]() is equivalent to \f[B]pmemobj_realloc\f[](), except that if the new size is larger than the old size, the added memory will be zeroed. .PP The \f[B]pmemobj_strdup\f[]() function stores a handle to a new object in \f[I]oidp\f[] which is a duplicate of the string \f[I]s\f[]. \f[B]pmemobj_strdup\f[]() provides the same semantics as \f[B]strdup\f[](3), but operates on the persistent memory heap associated with memory pool \f[I]pop\f[]. If \f[I]oidp\f[] is NULL, then the newly allocated object may be accessed only by iterating objects in the object container associated with type number \f[I]type_num\f[], as described in \f[B]POBJ_FOREACH\f[](3). If \f[I]oidp\f[] points to a memory location from the \f[B]pmemobj\f[] heap, \f[I]oidp\f[] is modified atomically. The allocated string object is also added to the internal container associated with type number \f[I]type_num\f[]. Memory for the new string is obtained with \f[B]pmemobj_alloc\f[](), on the given memory pool, and can be freed with \f[B]pmemobj_free\f[]() on the same memory pool. .PP \f[B]pmemobj_wcsdup\f[]() is equivalent to \f[B]pmemobj_strdup\f[](), but operates on a wide character string (wchar_t) rather than a standard character string. .PP The \f[B]pmemobj_alloc_usable_size\f[]() function provides the same semantics as \f[B]malloc_usable_size\f[](3), but instead of the process heap supplied by the system, it operates on the persistent memory heap. .PP The \f[B]POBJ_NEW\f[]() macro is a wrapper around the \f[B]pmemobj_alloc\f[]() function. Instead of taking a pointer to \f[I]PMEMoid\f[], it takes a pointer to the typed \f[I]OID\f[] of type name \f[I]TYPE\f[], and passes the size and type number from the typed \f[I]OID\f[] to \f[B]pmemobj_alloc\f[](). .PP The \f[B]POBJ_ALLOC\f[]() macro is equivalent to \f[B]POBJ_NEW\f[], except that instead of using the size of the typed \f[I]OID\f[], passes \f[I]size\f[] to \f[B]pmemobj_alloc\f[](). .PP The \f[B]POBJ_ZNEW\f[]() macro is a wrapper around the \f[B]pmemobj_zalloc\f[]() function. Instead of taking a pointer to \f[I]PMEMoid\f[], it takes a pointer to the typed \f[I]OID\f[] of type name \f[I]TYPE\f[], and passes the size and type number from the typed \f[I]OID\f[] to \f[B]pmemobj_zalloc\f[](). .PP The \f[B]POBJ_ZALLOC\f[]() macro is equivalent to \f[B]POBJ_ZNEW\f[], except that instead of using the size of the typed \f[I]OID\f[], passes \f[I]size\f[] to \f[B]pmemobj_zalloc\f[](). .PP The \f[B]POBJ_REALLOC\f[]() macro is a wrapper around the \f[B]pmemobj_realloc\f[]() function. Instead of taking a pointer to \f[I]PMEMoid\f[], it takes a pointer to the typed \f[I]OID\f[] of type name \f[I]TYPE\f[], and passes the type number from the typed \f[I]OID\f[] to \f[B]pmemobj_realloc\f[](). .PP The \f[B]POBJ_ZREALLOC\f[]() macro is a wrapper around the \f[B]pmemobj_zrealloc\f[]() function. Instead of taking a pointer to \f[I]PMEMoid\f[], it takes a pointer to the typed \f[I]OID\f[] of type name \f[I]TYPE\f[], and passes the type number from the typed \f[I]OID\f[] to \f[B]pmemobj_zrealloc\f[](). .PP The \f[B]POBJ_FREE\f[]() macro is a wrapper around the \f[B]pmemobj_free\f[]() function which takes a pointer to the typed \f[I]OID\f[] instead of to \f[I]PMEMoid\f[]. .SH RETURN VALUE .PP On success, \f[B]pmemobj_alloc\f[]() and \f[B]pmemobj_xalloc\f[] return 0. If \f[I]oidp\f[] is not NULL, the \f[I]PMEMoid\f[] of the newly allocated object is stored in \f[I]oidp\f[]. If the allocation fails, \-1 is returned and \f[I]errno\f[] is set appropriately. If the constructor returns a non\-zero value, the allocation is canceled, \-1 is returned, and \f[I]errno\f[] is set to \f[B]ECANCELED\f[]. If \f[I]size\f[] equals 0, or the \f[I]flags\f[] for \f[B]pmemobj_xalloc\f[] are invalid, \-1 is returned, \f[I]errno\f[] is set to \f[B]EINVAL\f[], and \f[I]oidp\f[] is left untouched. .PP On success, \f[B]pmemobj_zalloc\f[]() returns 0. If \f[I]oidp\f[] is not NULL, the \f[I]PMEMoid\f[] of the newly allocated object is stored in \f[I]oidp\f[]. If the allocation fails, it returns \-1 and sets \f[I]errno\f[] appropriately. If \f[I]size\f[] equals 0, it returns \-1, sets \f[I]errno\f[] to \f[B]EINVAL\f[], and leaves \f[I]oidp\f[] untouched. .PP The \f[B]pmemobj_free\f[]() function returns no value. .PP On success, \f[B]pmemobj_realloc\f[]() and \f[B]pmemobj_zrealloc\f[]() return 0 and update \f[I]oidp\f[] if necessary. On error, they return \-1 and set \f[I]errno\f[] appropriately. .PP On success, \f[B]pmemobj_strdup\f[]() and \f[B]pmemobj_wcsdup\f[]() return 0. If \f[I]oidp\f[] is not NULL, the \f[I]PMEMoid\f[] of the duplicated string object is stored in \f[I]oidp\f[]. If \f[I]s\f[] is NULL, they return \-1, set \f[I]errno\f[] to \f[B]EINVAL\f[], and leave \f[I]oidp\f[] untouched. On other errors, they return \-1 and set \f[I]errno\f[] appropriately. .PP The \f[B]pmemobj_alloc_usable_size\f[]() function returns the number of usable bytes in the object represented by \f[I]oid\f[]. If \f[I]oid\f[] is \f[B]OID_NULL\f[], it returns 0. .SH SEE ALSO .PP \f[B]free\f[](3), \f[B]POBJ_FOREACH\f[](3), \f[B]realloc\f[](3), \f[B]strdup\f[](3), \f[B]wcsdup\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_alloc_usable_size.3000066400000000000000000000000241331545616200224310ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_cancel.3000066400000000000000000000000261331545616200202010ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pmemobj_check.3000066400000000000000000000000231331545616200200260ustar00rootroot00000000000000.so pmemobj_open.3 pmdk-1.4.1/doc/generated/pmemobj_check_version.3000066400000000000000000000000261331545616200215760ustar00rootroot00000000000000.so man7/libpmemobj.7 pmdk-1.4.1/doc/generated/pmemobj_close.3000066400000000000000000000000231331545616200200560ustar00rootroot00000000000000.so pmemobj_open.3 pmdk-1.4.1/doc/generated/pmemobj_cond_broadcast.3000066400000000000000000000000311331545616200217150ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_cond_signal.3000066400000000000000000000000311331545616200212300ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_cond_timedwait.3000066400000000000000000000000311331545616200217420ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_cond_wait.3000066400000000000000000000000311331545616200207170ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_cond_zero.3000066400000000000000000000000311331545616200207320ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_create.3000066400000000000000000000000231331545616200202140ustar00rootroot00000000000000.so pmemobj_open.3 pmdk-1.4.1/doc/generated/pmemobj_ctl_exec.3000066400000000000000000000000261331545616200205420ustar00rootroot00000000000000.so pmemobj_ctl_get.3 pmdk-1.4.1/doc/generated/pmemobj_ctl_get.3000066400000000000000000000425701331545616200204070ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_CTL_GET" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_ctl_get\f[](), \f[B]pmemobj_ctl_set\f[](), \f[B]pmemobj_ctl_exec\f[]() \[en] Query and modify libpmemobj internal behavior (EXPERIMENTAL) .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmemobj_ctl_get(PMEMobjpool\ *pop,\ const\ char\ *name,\ void\ *arg);\ (EXPERIMENTAL) int\ pmemobj_ctl_set(PMEMobjpool\ *pop,\ const\ char\ *name,\ void\ *arg);\ (EXPERIMENTAL) int\ pmemobj_ctl_exec(PMEMobjpool\ *pop,\ const\ char\ *name,\ void\ *arg);\ (EXPERIMENTAL) \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemobj_ctl_get\f[](), \f[B]pmemobj_ctl_set\f[]() and \f[B]pmemobj_ctl_exec\f[]() functions provide a uniform interface for querying and modifying the internal behavior of \f[B]libpmemobj\f[] through the control (CTL) namespace. .PP The CTL namespace is organized in a tree structure. Starting from the root, each node can be either internal, containing other elements, or a leaf. Internal nodes themselves can only contain other nodes and cannot be entry points. There are two types of those nodes: \f[I]named\f[] and \f[I]indexed\f[]. Named nodes have string identifiers. Indexed nodes represent an abstract array index and have an associated string identifier. The index itself is provided by the user. A collection of indexes present on the path of an entry point is provided to the handler functions as name and index pairs. .PP The \f[I]name\f[] argument specifies an entry point as defined in the CTL namespace specification. The entry point description specifies whether the extra \f[I]arg\f[] is required. Those two parameters together create a CTL query. The \f[I]pop\f[] argument is optional if the entry point resides in a global namespace (i.e., is shared for all the pools). The functions and the entry points are thread\-safe unless indicated otherwise below. If there are special conditions for calling an entry point, they are explicitly stated in its description. The functions propagate the return value of the entry point. If either \f[I]name\f[] or \f[I]arg\f[] is invalid, \-1 is returned. .PP Entry points are the leaves of the CTL namespace structure. Each entry point can read from the internal state, write to the internal state, exec a function or a combination of these operations. .PP The entry points are listed in the following format: .PP name | r(ead)w(rite)x(ecute) | global/\- | read argument type | write argument type | exec argument type | config argument type .PP description\&... .SH CTL NAMESPACE .PP prefault.at_create | rw | global | int | int | \- | boolean .PP If set, every page of the pool will be touched and written to when the pool is created, in order to trigger page allocation and minimize the performance impact of pagefaults. Affects only the \f[B]pmemobj_create\f[]() function. .PP Always returns 0. .PP prefault.at_open | rw | global | int | int | \- | boolean .PP If set, every page of the pool will be touched and written to when the pool is opened, in order to trigger page allocation and minimize the performance impact of pagefaults. Affects only the \f[B]pmemobj_open\f[]() function. .PP Always returns 0. .PP tx.debug.skip_expensive_checks | rw | \- | int | int | \- | boolean .PP Turns off some expensive checks performed by the transaction module in \[lq]debug\[rq] builds. Ignored in \[lq]release\[rq] builds. .PP tx.cache.size | rw | \- | long long | long long | \- | integer .PP Size in bytes of the transaction snapshot cache. In a larger cache the frequency of persistent allocations is lower, but with higher fixed cost. .PP This should be set to roughly the sum of sizes of the snapshotted regions in an average transaction in the pool. .PP This value must be a in a range between 0 and \f[B]PMEMOBJ_MAX_ALLOC_SIZE\f[]. If the current threshold is larger than the new cache size, the threshold will be made equal to the new size. .PP This entry point is not thread safe and should not be modified if there are any transactions currently running. .PP Returns 0 if successful, \-1 otherwise. .PP tx.cache.threshold | rw | \- | long long | long long | \- | integer .PP Threshold in bytes, below which snapshots will use the cache. All larger snapshots will trigger a persistent allocation. .PP This value must be a in a range between 0 and \f[B]tx.cache.size\f[]. .PP This entry point is not thread safe and should not be modified if there are any transactions currently running. .PP Returns 0 if successful, \-1 otherwise. .PP tx.post_commit.queue_depth | rw | \- | int | int | \- | integer .PP Controls the depth of the post\-commit tasks queue. A post\-commit task is the collection of work items that need to be performed on the persistent state after a successfully completed transaction. This includes freeing no longer needed objects and cleaning up various caches. By default, this queue does not exist and the post\-commit task is executed synchronously in the same thread that ran the transaction. By changing this parameter, one can offload this task to a separate worker. If the queue is full, the algorithm, instead of waiting, performs the post\-commit in the current thread. .PP The task is performed on a finite resource (lanes, of which there are 1024), and if the worker threads that process this queue are unable to keep up with the demand, regular threads might start to block waiting for that resource. This will happen if the queue depth value is too large. .PP As a general rule, this value should be set to approximately 1024 minus the average number of threads in the application (not counting the post\-commit workers); however, this may vary from workload to workload. .PP The queue depth value must also be a power of two. .PP This entry point is not thread\-safe and must be called when no transactions are currently being executed. .PP Returns 0 if successful, \-1 otherwise. .PP tx.post_commit.worker | r\- | \- | void * | \- | \- | \- .PP The worker function launched in a thread to perform asynchronous processing of post\-commit tasks. This function returns only after a stop entry point is called. There may be many worker threads at a time. If there is no work to be done, this function sleeps instead of polling. .PP Always returns 0. .PP tx.post_commit.stop | r\- | \- | void * | \- | \- | \- .PP This function forces all the post\-commit worker functions to exit and return control back to the calling thread. This should be called before the application terminates and the post commit worker threads need to be shutdown. .PP After the invocation of this entry point, the post\-commit task queue can no longer be used. If worker threads must be restarted after a stop, the tx.post_commit.queue_depth needs to be set again. .PP This entry point must be called when no transactions are currently being executed. .PP Always returns 0. .PP heap.alloc_class.[class_id].desc | rw | \- | \f[C]struct\ pobj_alloc_class_desc\f[] | \f[C]struct\ pobj_alloc_class_desc\f[] | \- | integer, integer, integer, string .PP Describes an allocation class. Allows one to create or view the internal data structures of the allocator. .PP Creating custom allocation classes can be beneficial for both raw allocation throughput, scalability and, most importantly, fragmentation. By carefully constructing allocation classes that match the application workload, one can entirely eliminate external and internal fragmentation. For example, it is possible to easily construct a slab\-like allocation mechanism for any data structure. .PP The \f[C][class_id]\f[] is an index field. Only values between 0\-254 are valid. If setting an allocation class, but the \f[C]class_id\f[] is already taken, the function will return \-1. The values between 0\-127 are reserved for the default allocation classes of the library and can be used only for reading. .PP The recommended method for retrieving information about all allocation classes is to call this entry point for all class ids between 0 and 254 and discard those results for which the function returns an error. .PP This entry point takes a complex argument. .IP .nf \f[C] struct\ pobj_alloc_class_desc\ { \ \ \ \ size_t\ unit_size; \ \ \ \ size_t\ alignment; \ \ \ \ unsigned\ units_per_block; \ \ \ \ enum\ pobj_header_type\ header_type; \ \ \ \ unsigned\ class_id; }; \f[] .fi .PP The first field, \f[C]unit_size\f[], is an 8\-byte unsigned integer that defines the allocation class size. While theoretically limited only by \f[B]PMEMOBJ_MAX_ALLOC_SIZE\f[], for most workloads this value should be between 8 bytes and 2 megabytes. .PP The \f[C]alignment\f[] field is currently unsupported and must be set to 0. All objects have default alignment of 64 bytes, but the user data alignment is affected by the size of the chosen header. .PP The \f[C]units_per_block\f[] field defines how many units a single block of memory contains. This value will be rounded up to match the internal size of the block (256 kilobytes or a multiple thereof). For example, given a class with a \f[C]unit_size\f[] of 512 bytes and a \f[C]units_per_block\f[] of 1000, a single block of memory for that class will have 512 kilobytes. This is relevant because the bigger the block size, the less frequently blocks need to be fetched, resulting in lower contention on global heap state. Keep in mind that object allocation is tracked in a bitmap with a limited number of entries, making it inefficient to create allocation classes smaller than 128 bytes. .PP The \f[C]header_type\f[] field defines the header of objects from the allocation class. There are three types: .IP \[bu] 2 \f[B]POBJ_HEADER_LEGACY\f[], string value: \f[C]legacy\f[]. Used for allocation classes prior to version 1.3 of the library. Not recommended for use. Incurs a 64 byte metadata overhead for every object. Fully supports all features. .IP \[bu] 2 \f[B]POBJ_HEADER_COMPACT\f[], string value: \f[C]compact\f[]. Used as default for all predefined allocation classes. Incurs a 16 byte metadata overhead for every object. Fully supports all features. .IP \[bu] 2 \f[B]POBJ_HEADER_NONE\f[], string value: \f[C]none\f[]. Header type that incurs no metadata overhead beyond a single bitmap entry. Can be used for very small allocation classes or when objects must be adjacent to each other. This header type does not support type numbers (type number is always .RS 2 .IP "0)" 3 or allocations that span more than one unit. .RE .PP The \f[C]class_id\f[] field is an optional, runtime\-only variable that allows the user to retrieve the identifier of the class. This will be equivalent to the provided \f[C][class_id]\f[]. This field cannot be set from a config file. .PP The allocation classes are a runtime state of the library and must be created after every open. It is highly recommended to use the configuration file to store the classes. .PP This structure is declared in the \f[C]libpmemobj/ctl.h\f[] header file. Please refer to this file for an in\-depth explanation of the allocation classes and relevant algorithms. .PP Allocation classes constructed in this way can be leveraged by explicitly specifying the class using \f[B]POBJ_CLASS_ID(id)\f[] flag in \f[B]pmemobj_tx_xalloc\f[]()/\f[B]pmemobj_xalloc\f[]() functions. .PP Example of a valid alloc class query string: .IP .nf \f[C] heap.alloc_class.128.desc=500,0,1000,compact \f[] .fi .PP This query, if executed, will create an allocation class with an id of 128 that has a unit size of 500 bytes, has at least 1000 units per block and uses a compact header. .PP For reading, function returns 0 if successful, if the allocation class does not exist it sets the errno to \f[B]ENOENT\f[] and returns \-1; .PP For writing, function returns 0 if the allocation class has been successfully created, \-1 otherwise. .PP heap.alloc_class.new.desc | \-w | \- | \- | \f[C]struct\ pobj_alloc_class_desc\f[] | \- | integer, integer, integer, string .PP Same as \f[C]heap.alloc_class.[class_id].desc\f[], but instead of requiring the user to provide the class_id, it automatically creates the allocation class with the first available identifier. .PP This should be used when it's impossible to guarantee unique allocation class naming in the application (e.g.\ when writing a library that uses libpmemobj). .PP The required class identifier will be stored in the \f[C]class_id\f[] field of the \f[C]struct\ pobj_alloc_class_desc\f[]. .PP This function returns 0 if the allocation class has been successfully created, \-1 otherwise. .PP stats.enabled | rw | \- | int | int | \- | boolean .PP Enables or disables runtime collection of statistics. Statistics are not recalculated after enabling; any operations that occur between disabling and re\-enabling will not be reflected in subsequent values. .PP Statistics are disabled by default. Enabling them may have non\-trivial performance impact. .PP Always returns 0. .PP stats.heap.curr_allocated | r\- | \- | int | \- | \- | \- .PP Returns the number of bytes currently allocated in the heap. If statistics were disabled at any time in the lifetime of the heap, this value may be inaccurate. .PP heap.size.granularity | rw\- | \- | uint64_t | uint64_t | \- | long long .PP Reads or modifies the granularity with which the heap grows when OOM. Valid only if the poolset has been defined with directories. .PP A granularity of 0 specifies that the pool will not grow automatically. .PP This function returns 0 if the granularity value is 0, or is larger than \f[I]PMEMOBJ_MIN_PART\f[], \-1 otherwise. .PP heap.size.extend | \[en]x | \- | \- | \- | uint64_t | \- .PP Extends the heap by the given size. Must be larger than \f[I]PMEMOBJ_MIN_PART\f[]. .PP This function returns 0 if successful, \-1 otherwise. .SH CTL EXTERNAL CONFIGURATION .PP In addition to direct function call, each write entry point can also be set using two alternative methods. .PP The first method is to load a configuration directly from the \f[B]PMEMOBJ_CONF\f[] environment variable. A properly formatted ctl config string is a single\-line sequence of queries separated by `;': .IP .nf \f[C] query0;query1;...;queryN \f[] .fi .PP A single query is constructed from the name of the ctl write entry point and the argument, separated by `=': .IP .nf \f[C] entry_point=entry_point_argument \f[] .fi .PP The entry point argument type is defined by the entry point itself, but there are three predefined primitives: .IP .nf \f[C] *)\ integer:\ represented\ by\ a\ sequence\ of\ [0\-9]\ characters\ that\ form \ \ \ \ a\ single\ number. *)\ boolean:\ represented\ by\ a\ single\ character:\ y/n/Y/N/0/1,\ each \ \ \ \ corresponds\ to\ true\ or\ false.\ If\ the\ argument\ contains\ any \ \ \ \ trailing\ characters,\ they\ are\ ignored. *)\ string:\ a\ simple\ sequence\ of\ characters. \f[] .fi .PP There are also complex argument types that are formed from the primitives separated by a `,': .IP .nf \f[C] first_arg,second_arg \f[] .fi .PP In summary, a full configuration sequence looks like this: .IP .nf \f[C] (first_entry_point)=(arguments,\ ...);...;(last_entry_point)=(arguments,\ ...); \f[] .fi .PP As an example, to set both prefault at_open and at_create variables: .IP .nf \f[C] PMEMOBJ_CONF="prefault.at_open=1;prefault.at_create=1" \f[] .fi .PP The second method of loading an external configuration is to set the \f[B]PMEMOBJ_CONF_FILE\f[] environment variable to point to a file that contains a sequence of ctl queries. The parsing rules are all the same, but the file can also contain white\-spaces and comments. .PP To create a comment, simply use `#' anywhere in a line and everything afterwards, until a new line `', will be ignored. .PP An example configuration file: .IP .nf \f[C] ######################### #\ My\ pmemobj\ configuration ######################### # #\ Global\ settings: prefault.\ #\ modify\ the\ behavior\ of\ pre\-faulting \ \ \ \ at_open\ =\ 1;\ #\ prefault\ when\ the\ pool\ is\ opened prefault. \ \ \ \ at_create\ =\ 0;\ #\ but\ don\[aq]t\ prefault\ when\ it\[aq]s\ created #\ Per\-pool\ settings: #\ ... \f[] .fi .SH SEE ALSO .PP \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_ctl_set.3000066400000000000000000000000261331545616200204110ustar00rootroot00000000000000.so pmemobj_ctl_get.3 pmdk-1.4.1/doc/generated/pmemobj_direct.3000066400000000000000000000000221331545616200202220ustar00rootroot00000000000000.so oid_is_null.3 pmdk-1.4.1/doc/generated/pmemobj_drain.3000066400000000000000000000000351331545616200200510ustar00rootroot00000000000000.so pmemobj_memcpy_persist.3 pmdk-1.4.1/doc/generated/pmemobj_errormsg.3000066400000000000000000000000261331545616200206140ustar00rootroot00000000000000.so man7/libpmemobj.7 pmdk-1.4.1/doc/generated/pmemobj_first.3000066400000000000000000000122371331545616200201120ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_FIRST" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_first\f[](), \f[B]pmemobj_next\f[](), \f[B]POBJ_FIRST\f[](), \f[B]POBJ_FIRST_TYPE_NUM\f[](), \f[B]POBJ_NEXT\f[](), \f[B]POBJ_NEXT_TYPE_NUM\f[](), \f[B]POBJ_FOREACH\f[](), \f[B]POBJ_FOREACH_SAFE\f[](), \f[B]POBJ_FOREACH_TYPE\f[](), \f[B]POBJ_FOREACH_SAFE_TYPE\f[]() \[en] pmemobj container operations .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMoid\ pmemobj_first(PMEMobjpool\ *pop); PMEMoid\ pmemobj_next(PMEMoid\ oid); POBJ_FIRST(PMEMobjpool\ *pop,\ TYPE) POBJ_FIRST_TYPE_NUM(PMEMobjpool\ *pop,\ uint64_t\ type_num) POBJ_NEXT(TOID\ oid) POBJ_NEXT_TYPE_NUM(PMEMoid\ oid) POBJ_FOREACH(PMEMobjpool\ *pop,\ PMEMoid\ varoid) POBJ_FOREACH_SAFE(PMEMobjpool\ *pop,\ PMEMoid\ varoid,\ PMEMoid\ nvaroid) POBJ_FOREACH_TYPE(PMEMobjpool\ *pop,\ TOID\ var) POBJ_FOREACH_SAFE_TYPE(PMEMobjpool\ *pop,\ TOID\ var,\ TOID\ nvar) \f[] .fi .SH DESCRIPTION .PP The \f[B]libpmemobj\f[](7) container operations provide a mechanism that allows iteration through the internal object collection, either looking for a specific object, or performing a specific operation on each object of a given type. Software should not make any assumptions about the order of the objects in the internal object containers. .PP The \f[B]pmemobj_first\f[]() function returns the first object from the pool. .PP The \f[B]POBJ_FIRST\f[]() macro returns the first object from the pool of the type specified by \f[I]TYPE\f[]. .PP The \f[B]POBJ_FIRST_TYPE_NUM\f[]() macro returns the first object from the pool of the type specified by \f[I]type_num\f[]. .PP The \f[B]pmemobj_next\f[]() function returns the next object from the pool. .PP The \f[B]POBJ_NEXT\f[]() macro returns the next object of the same type as the object referenced by \f[I]oid\f[]. .PP The \f[B]POBJ_NEXT_TYPE_NUM\f[]() macro returns the next object of the same type number as the object referenced by \f[I]oid\f[]. .PP The following four macros provide a more convenient way to iterate through the internal collections, performing a specific operation on each object. .PP The \f[B]POBJ_FOREACH\f[]() macro performs a specific operation on each allocated object stored in the persistent memory pool \f[I]pop\f[]. It traverses the internal collection of all the objects, assigning a handle to each element in turn to \f[I]varoid\f[]. .PP The \f[B]POBJ_FOREACH_TYPE\f[]() macro performs a specific operation on each allocated object stored in the persistent memory pool \f[I]pop\f[] that has the same type as \f[I]var\f[]. It traverses the internal collection of all the objects of the specified type, assigning a handle to each element in turn to \f[I]var\f[]. .PP The macros \f[B]POBJ_FOREACH_SAFE\f[]() and \f[B]POBJ_FOREACH_SAFE_TYPE\f[]() work in a similar fashion as \f[B]POBJ_FOREACH\f[]() and \f[B]POBJ_FOREACH_TYPE\f[](), except that prior to performing the operation on the object, they preserve a handle to the next object in the collection by assigning it to \f[I]nvaroid\f[] or \f[I]nvar\f[], respectively. This allows safe deletion of selected objects while iterating through the collection. .SH RETURN VALUE .PP \f[B]pmemobj_first\f[]() returns the first object from the pool, or, if the pool is empty, \f[B]OID_NULL\f[]. .PP \f[B]pmemobj_next\f[]() returns the next object from the pool. If the object referenced by \f[I]oid\f[] is the last object in the collection, or if \f[I]oid\f[] is \f[I]OID_NULL\f[], \f[B]pmemobj_next\f[]() returns \f[B]OID_NULL\f[]. .SH SEE ALSO .PP \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_flush.3000066400000000000000000000000351331545616200200750ustar00rootroot00000000000000.so pmemobj_memcpy_persist.3 pmdk-1.4.1/doc/generated/pmemobj_free.3000066400000000000000000000000241331545616200176730ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_list_insert.3000066400000000000000000000230401331545616200213140ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_LIST_INSERT" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_list_insert\f[](), \f[B]pmemobj_list_insert_new\f[](), \f[B]pmemobj_list_move\f[](), \f[B]pmemobj_list_remove\f[]() \[en] non\-transactional persistent atomic lists functions .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmemobj_list_insert(PMEMobjpool\ *pop,\ size_t\ pe_offset,\ void\ *head, \ \ \ \ PMEMoid\ dest,\ int\ before,\ PMEMoid\ oid); PMEMoid\ pmemobj_list_insert_new(PMEMobjpool\ *pop,\ size_t\ pe_offset, \ \ \ \ void\ *head,\ PMEMoid\ dest,\ int\ before,\ size_t\ size, \ \ \ \ uint64_t\ type_num,\ pmemobj_constr\ constructor,\ void\ arg); int\ pmemobj_list_move(PMEMobjpool\ *pop, \ \ \ \ size_t\ pe_old_offset,\ void\ *head_old, \ \ \ \ size_t\ pe_new_offset,\ void\ *head_new, \ \ \ \ PMEMoid\ dest,\ int\ before,\ PMEMoid\ oid); int\ pmemobj_list_remove(PMEMobjpool\ *pop,\ size_t\ pe_offset, \ \ \ \ void\ *head,\ PMEMoid\ oid,\ int\ free); \f[] .fi .SH DESCRIPTION .PP In addition to the container operations on internal object collections described in \f[B]pmemobj_first\f[](3), \f[B]libpmemobj\f[](7) provides a mechanism for organizing persistent objects in user\-defined, persistent, atomic, circular, doubly\-linked lists. All the routines and macros operating on the persistent lists provide atomicity with respect to any power\-fail interruptions. If any of those operations is torn by program failure or system crash, on recovery they are guaranteed to be entirely completed or discarded, leaving the lists, persistent memory heap and internal object containers in a consistent state. .PP The persistent atomic circular doubly linked lists support the following functionality: .IP \[bu] 2 Insertion of an object at the head of the list, or at the end of the list. .IP \[bu] 2 Insertion of an object before or after any element in the list. .IP \[bu] 2 Atomic allocation and insertion of a new object at the head of the list, or at the end of the list. .IP \[bu] 2 Atomic allocation and insertion of a new object before or after any element in the list. .IP \[bu] 2 Atomic moving of an element from one list to the specific location on another list. .IP \[bu] 2 Removal of any object in the list. .IP \[bu] 2 Atomic removal and freeing of any object in the list. .IP \[bu] 2 Forward or backward traversal through the list. .PP A list is headed by a \f[I]list_head\f[] structure containing the object handle of the first element on the list. The elements are doubly linked so that an arbitrary element can be removed without the need to traverse the list. New elements can be added to the list before or after an existing element, at the head of the list, or at the tail of the list. A list may be traversed in either direction. .PP The user\-defined structure of each element must contain a field of type \f[I]list_entry\f[] that holds the object handles to the previous and next element on the list. Both the \f[I]list_head\f[] and the \f[I]list_entry\f[] structures are declared in \f[B]\f[]. .PP The functions below are intended to be used outside transactions \- transactional variants are described in manpages to functions mentioned at \f[B]TRANSACTIONAL OBJECT MANIPULATION\f[] in \f[B]libpmemobj\f[](7). Note that operations performed using this non\-transactional API are independent from their transactional counterparts. If any non\-transactional allocations or list manipulations are performed within an open transaction, the changes will not be rolled back if such a transaction is aborted or interrupted. .PP The list insertion and move functions use a common set of arguments to define where an object will be inserted into the list. \f[I]dest\f[] identifies the element before or after which the object will be inserted, or, if \f[I]dest\f[] is \f[B]OID_NULL\f[], indicates that the object should be inserted at the head or tail of the list. \f[I]before\f[] determines where the object will be inserted: .IP \[bu] 2 \f[B]POBJ_LIST_DEST_BEFORE\f[] \- insert the element before the existing element \f[I]dest\f[] .IP \[bu] 2 \f[B]POBJ_LIST_DEST_AFTER\f[] \- insert the element after the existing element \f[I]dest\f[] .IP \[bu] 2 \f[B]POBJ_LIST_DEST_HEAD\f[] \- when \f[I]dest\f[] is \f[B]OID_NULL\f[], insert the element at the head of the list .IP \[bu] 2 \f[B]POBJ_LIST_DEST_TAIL\f[] \- when \f[I]dest\f[] is \f[B]OID_NULL\f[], insert the element at the tail of the list .RS .PP NOTE: Earlier versions of \f[B]libpmemobj\f[](7) do not define \f[B]POBJ_LIST_DEST_BEFORE\f[] and \f[B]POBJ_LIST_DEST_AFTER\f[]. Use 1 for before, and 0 for after. .RE .PP The \f[B]pmemobj_list_insert\f[]() function inserts the element represented by object handle \f[I]oid\f[] into the list referenced by \f[I]head\f[], at the location specified by \f[I]dest\f[] and \f[I]before\f[] as described above. \f[I]pe_offset\f[] specifies the offset of the structure that connects the elements in the list. All the handles \f[I]head\f[], \f[I]dest\f[] and \f[I]oid\f[] must point to objects allocated from memory pool \f[I]pop\f[]. \f[I]head\f[] and \f[I]oid\f[] cannot be \f[B]OID_NULL\f[]. .PP The \f[B]pmemobj_list_insert_new\f[]() function atomically allocates a new object of given \f[I]size\f[] and type \f[I]type_num\f[] and inserts it into the list referenced by \f[I]head\f[] at the location specified by \f[I]dest\f[] and \f[I]before\f[] as described above. \f[I]pe_offset\f[] specifies the offset of the structure that connects the elements in the list. The handles \f[I]head\f[] and \f[I]dest\f[] must point to objects allocated from memory pool \f[I]pop\f[]. Before returning, \f[B]pmemobj_list_insert_new\f[]() calls the \f[I]constructor\f[] function, passing the pool handle \f[I]pop\f[], the pointer to the newly allocated object \f[I]ptr\f[], and the \f[I]arg\f[] argument. It is guaranteed that the allocated object is either properly initialized or, if the allocation is interrupted before the constructor completes, the memory space reserved for the object is reclaimed. \f[I]head\f[] cannot be \f[B]OID_NULL\f[]. The allocated object is also added to the internal container associated with \f[I]type_num\f[], as described in \f[B]POBJ_FOREACH\f[](3). .PP The \f[B]pmemobj_list_move\f[]() function moves the object represented by object handle \f[I]oid\f[] from the list referenced by \f[I]head_old\f[] to the list referenced by \f[I]head_new\f[], inserting it at the location specified by \f[I]dest\f[] and \f[I]before\f[] as described above. \f[I]pe_old_offset\f[] and \f[I]pe_new_offset\f[] specify the offsets of the structures that connect the elements in the old and new lists, respectively. All the handles \f[I]head_old\f[], \f[I]head_new\f[], \f[I]dest\f[] and \f[I]oid\f[] must point to objects allocated from memory pool \f[I]pop\f[]. \f[I]head_old\f[], \f[I]head_new\f[] and \f[I]oid\f[] cannot be \f[B]OID_NULL\f[]. .PP The \f[B]pmemobj_list_remove\f[]() function removes the object represented by object handle \f[I]oid\f[] from the list referenced by \f[I]head\f[]. If \f[I]free\f[] is set, it also removes the object from the internal object container and frees the associated memory space. \f[I]pe_offset\f[] specifies the offset of the structure that connects the elements in the list. Both \f[I]head\f[] and \f[I]oid\f[] must point to objects allocated from memory pool \f[I]pop\f[] and cannot be \f[B]OID_NULL\f[]. .SH RETURN VALUE .PP On success, \f[B]pmemobj_list_insert\f[](), \f[B]pmemobj_list_remove\f[]() and \f[B]pmemobj_list_move\f[]() return 0. On error, they return \-1 and set \f[I]errno\f[] appropriately. .PP On success, \f[B]pmemobj_list_insert_new\f[]() returns a handle to the newly allocated object. If the constructor returns a non\-zero value, the allocation is canceled, \-1 is returned, and \f[I]errno\f[] is set to \f[B]ECANCELED\f[]. On other errors, \f[B]OID_NULL\f[] is returned and \f[I]errno\f[] is set appropriately. .SH SEE ALSO .PP \f[B]pmemobj_first\f[](3), \f[B]POBJ_FOREACH\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_list_insert_new.3000066400000000000000000000000321331545616200221610ustar00rootroot00000000000000.so pmemobj_list_insert.3 pmdk-1.4.1/doc/generated/pmemobj_list_move.3000066400000000000000000000000321331545616200207520ustar00rootroot00000000000000.so pmemobj_list_insert.3 pmdk-1.4.1/doc/generated/pmemobj_list_remove.3000066400000000000000000000000321331545616200213010ustar00rootroot00000000000000.so pmemobj_list_insert.3 pmdk-1.4.1/doc/generated/pmemobj_memcpy_persist.3000066400000000000000000000133221331545616200220220ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_MEMCPY_PERSIST" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_memcpy_persist\f[](), \f[B]pmemobj_memset_persist\f[](), \f[B]pmemobj_persist\f[](), \f[B]pmemobj_flush\f[](), \f[B]pmemobj_drain\f[]() \[en] low\-level memory manipulation functions .SH SYNOPSIS .IP .nf \f[C] #include\ void\ *pmemobj_memcpy_persist(PMEMobjpool\ *pop,\ void\ *dest, \ \ \ \ const\ void\ *src,\ size_t\ len); void\ *pmemobj_memset_persist(PMEMobjpool\ *pop,\ void\ *dest, \ \ \ \ int\ c,\ size_t\ len); void\ pmemobj_persist(PMEMobjpool\ *pop,\ const\ void\ *addr, \ \ \ \ size_t\ len); void\ pmemobj_flush(PMEMobjpool\ *pop,\ const\ void\ *addr, \ \ \ \ size_t\ len); void\ pmemobj_drain(PMEMobjpool\ *pop); \f[] .fi .SH DESCRIPTION .PP The \f[B]libpmemobj\f[]\-specific low\-level memory manipulation functions described here leverage the knowledge of the additional configuration options available for \f[B]libpmemobj\f[](7) pools, such as replication. They also take advantage of the type of storage behind the pool and use appropriate flush/drain functions. It is advised to use these functions in conjunction with \f[B]libpmemobj\f[](7) objects rather than using low\-level memory manipulation functions from \f[B]libpmem\f[]. .PP The \f[B]pmemobj_memcpy_persist\f[]() and \f[B]pmemobj_memset_persist\f[]() functions provide the same memory copying as their namesakes \f[B]memcpy\f[](3), and \f[B]memset\f[](3), and ensure that the result has been flushed to persistence before returning. .PP \f[B]pmemobj_persist\f[]() forces any changes in the range [\f[I]addr\f[], \f[I]addr\f[]+\f[I]len\f[]) to be stored durably in persistent memory. Internally this may call either \f[B]pmem_msync\f[](3) or \f[B]pmem_persist\f[](3). There are no alignment restrictions on the range described by \f[I]addr\f[] and \f[I]len\f[], but \f[B]pmemobj_persist\f[]() may expand the range as necessary to meet platform alignment requirements. .RS .PP WARNING: Like \f[B]msync\f[](2), there is nothing atomic or transactional about this call. Any unwritten stores in the given range will be written, but some stores may have already been written by virtue of normal cache eviction/replacement policies. Correctly written code must not depend on stores waiting until \f[B]pmemobj_persist\f[]() is called to become persistent \- they can become persistent at any time before \f[B]pmemobj_persist\f[]() is called. .RE .PP The \f[B]pmemobj_flush\f[]() and \f[B]pmemobj_drain\f[]() functions provide partial versions of the \f[B]pmemobj_persist\f[]() function described above. These functions allow advanced programs to create their own variations of \f[B]pmemobj_persist\f[](). For example, a program that needs to flush several discontiguous ranges can call \f[B]pmemobj_flush\f[]() for each range and then follow up by calling \f[B]pmemobj_drain\f[]() once. For more information on partial flushing operations, see \f[B]pmem_flush\f[](3). .SH RETURN VALUE .PP The \f[B]pmemobj_memcpy_persist\f[]() and \f[B]pmemobj_memset_persist\f[]() functions return the same values as their namesakes \f[B]memcpy\f[](3), and \f[B]memset\f[](3). .PP \f[B]pmemobj_persist\f[](), \f[B]pmemobj_flush\f[]() and \f[B]pmemobj_drain\f[]() return no value. .SH EXAMPLES .PP The following code is functionally equivalent to \f[B]pmemobj_memcpy_persist\f[](): .IP .nf \f[C] void\ * pmemobj_memcpy_persist(PMEMobjpool\ *pop,\ void\ *dest, \ \ \ \ const\ void\ *src,\ size_t\ len) { \ \ \ \ void\ *retval\ =\ memcpy(dest,\ src,\ len); \ \ \ \ pmemobj_persist(pop,\ dest,\ len); \ \ \ \ return\ retval; } \f[] .fi .PP \f[B]pmemobj_persist\f[]() can be thought of as this: .IP .nf \f[C] void pmemobj_persist(PMEMobjpool\ *pop,\ const\ void\ *addr,\ size_t\ len) { \ \ \ \ /*\ flush\ the\ processor\ caches\ */ \ \ \ \ pmemobj_flush(pop,\ addr,\ len); \ \ \ \ /*\ wait\ for\ any\ pmem\ stores\ to\ drain\ from\ HW\ buffers\ */ \ \ \ \ pmemobj_drain(pop); } \f[] .fi .SH SEE ALSO .PP \f[B]memcpy\f[](3), \f[B]memset\f[](3), \f[B]pmem_msync\f[](3), \f[B]pmem_persist\f[](3), \f[B]libpmem\f[](7) \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_memset_persist.3000066400000000000000000000000351331545616200220170ustar00rootroot00000000000000.so pmemobj_memcpy_persist.3 pmdk-1.4.1/doc/generated/pmemobj_mutex_lock.3000066400000000000000000000000311331545616200211220ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_mutex_timedlock.3000066400000000000000000000000311331545616200221450ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_mutex_trylock.3000066400000000000000000000000311331545616200216610ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_mutex_unlock.3000066400000000000000000000000311331545616200214650ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_mutex_zero.3000066400000000000000000000270371331545616200211700ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_MUTEX_ZERO" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_mutex_zero\f[](), \f[B]pmemobj_mutex_lock\f[](), \f[B]pmemobj_mutex_timedlock\f[](), \f[B]pmemobj_mutex_trylock\f[](), \f[B]pmemobj_mutex_unlock\f[](), .PP \f[B]pmemobj_rwlock_zero\f[](), \f[B]pmemobj_rwlock_rdlock\f[](), \f[B]pmemobj_rwlock_wrlock\f[](), \f[B]pmemobj_rwlock_timedrdlock\f[](), \f[B]pmemobj_rwlock_timedwrlock\f[](), \f[B]pmemobj_rwlock_tryrdlock\f[](), \f[B]pmemobj_rwlock_trywrlock\f[](), \f[B]pmemobj_rwlock_unlock\f[](), .PP \f[B]pmemobj_cond_zero\f[](), \f[B]pmemobj_cond_broadcast\f[](), \f[B]pmemobj_cond_signal\f[](), \f[B]pmemobj_cond_timedwait\f[](), \f[B]pmemobj_cond_wait\f[]() \[en] pmemobj synchronization primitives .SH SYNOPSIS .IP .nf \f[C] #include\ void\ pmemobj_mutex_zero(PMEMobjpool\ *pop,\ PMEMmutex\ *mutexp); int\ pmemobj_mutex_lock(PMEMobjpool\ *pop,\ PMEMmutex\ *mutexp); int\ pmemobj_mutex_timedlock(PMEMobjpool\ *pop,\ PMEMmutex\ *restrict\ mutexp, \ \ \ \ const\ struct\ timespec\ *restrict\ abs_timeout); int\ pmemobj_mutex_trylock(PMEMobjpool\ *pop,\ PMEMmutex\ *mutexp); int\ pmemobj_mutex_unlock(PMEMobjpool\ *pop,\ PMEMmutex\ *mutexp); void\ pmemobj_rwlock_zero(PMEMobjpool\ *pop,\ PMEMrwlock\ *rwlockp); int\ pmemobj_rwlock_rdlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *rwlockp); int\ pmemobj_rwlock_wrlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *rwlockp); int\ pmemobj_rwlock_timedrdlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *restrict\ rwlockp, \ \ \ \ const\ struct\ timespec\ *restrict\ abs_timeout); int\ pmemobj_rwlock_timedwrlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *restrict\ rwlockp, \ \ \ \ const\ struct\ timespec\ *restrict\ abs_timeout); int\ pmemobj_rwlock_tryrdlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *rwlockp); int\ pmemobj_rwlock_trywrlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *rwlockp); int\ pmemobj_rwlock_unlock(PMEMobjpool\ *pop,\ PMEMrwlock\ *rwlockp); void\ pmemobj_cond_zero(PMEMobjpool\ *pop,\ PMEMcond\ *condp); int\ pmemobj_cond_broadcast(PMEMobjpool\ *pop,\ PMEMcond\ *condp); int\ pmemobj_cond_signal(PMEMobjpool\ *pop,\ PMEMcond\ *condp); int\ pmemobj_cond_timedwait(PMEMobjpool\ *pop,\ PMEMcond\ *restrict\ condp, \ \ \ \ PMEMmutex\ *restrict\ mutexp,\ const\ struct\ timespec\ *restrict\ abs_timeout); int\ pmemobj_cond_wait(PMEMobjpool\ *pop,\ PMEMcond\ *restrict\ condp, \ \ \ \ PMEMmutex\ *restrict\ mutexp); \f[] .fi .SH DESCRIPTION .PP \f[B]libpmemobj\f[](7) provides several types of synchronization primitives designed to be used with persistent memory. The pmem\-aware lock implementation is based on the standard POSIX Threads Library, as described in \f[B]pthread_mutex_init\f[](3), \f[B]pthread_rwlock_init\f[](3) and \f[B]pthread_cond_init\f[](3). Pmem\-aware locks provide semantics similar to standard \f[B]pthread\f[] locks, except that they are embedded in pmem\-resident objects and are considered initialized by zeroing them. Therefore, locks allocated with \f[B]pmemobj_zalloc\f[](3) or \f[B]pmemobj_tx_zalloc\f[](3) do not require another initialization step. For performance reasons, they are also padded up to 64 bytes (cache line size). .PP On FreeBSD, since all \f[B]pthread\f[] locks are dynamically allocated, while the lock object is still padded up to 64 bytes for consistency with Linux, only the pointer to the lock is embedded in the pmem\-resident object. \f[B]libpmemobj\f[](7) transparently manages freeing of the locks when the pool is closed. .PP The fundamental property of pmem\-aware locks is their automatic reinitialization every time the persistent object store pool is opened. Thus, all the pmem\-aware locks may be considered initialized (unlocked) immediately after the pool is opened, regardless of their state at the time the pool was closed for the last time. .PP Pmem\-aware mutexes, read/write locks and condition variables must be declared with the \f[I]PMEMmutex\f[], \f[I]PMEMrwlock\f[], or \f[I]PMEMcond\f[] type, respectively. .PP The \f[B]pmemobj_mutex_zero\f[]() function explicitly initializes the pmem\-aware mutex \f[I]mutexp\f[] by zeroing it. Initialization is not necessary if the object containing the mutex has been allocated using \f[B]pmemobj_zalloc\f[](3) or \f[B]pmemobj_tx_zalloc\f[](3). .PP The \f[B]pmemobj_mutex_lock\f[]() function locks the pmem\-aware mutex \f[I]mutexp\f[]. If the mutex is already locked, the calling thread will block until the mutex becomes available. If this is the first use of the mutex since the opening of the pool \f[I]pop\f[], the mutex is automatically reinitialized and then locked. .PP \f[B]pmemobj_mutex_timedlock\f[]() performs the same action as \f[B]pmemobj_mutex_lock\f[](), but will not wait beyond \f[I]abs_timeout\f[] to obtain the lock before returning. .PP The \f[B]pmemobj_mutex_trylock\f[]() function locks pmem\-aware mutex \f[I]mutexp\f[]. If the mutex is already locked, \f[B]pthread_mutex_trylock\f[]() will not block waiting for the mutex, but will return an error. If this is the first use of the mutex since the opening of the pool \f[I]pop\f[], the mutex is automatically reinitialized and then locked. .PP The \f[B]pmemobj_mutex_unlock\f[]() function unlocks the pmem\-aware mutex \f[I]mutexp\f[]. Undefined behavior follows if a thread tries to unlock a mutex that has not been locked by it, or if a thread tries to release a mutex that is already unlocked or has not been initialized. .PP The \f[B]pmemobj_rwlock_zero\f[]() function is used to explicitly initialize the pmem\-aware read/write lock \f[I]rwlockp\f[] by zeroing it. Initialization is not necessary if the object containing the lock has been allocated using \f[B]pmemobj_zalloc\f[](3) or \f[B]pmemobj_tx_zalloc\f[](3). .PP The \f[B]pmemobj_rwlock_rdlock\f[]() function acquires a read lock on \f[I]rwlockp\f[], provided that the lock is not presently held for writing and no writer threads are presently blocked on the lock. If the read lock cannot be acquired immediately, the calling thread blocks until it can acquire the lock. If this is the first use of the lock since the opening of the pool \f[I]pop\f[], the lock is automatically reinitialized and then acquired. .PP \f[B]pmemobj_rwlock_timedrdlock\f[]() performs the same action as \f[B]pmemobj_rwlock_rdlock\f[](), but will not wait beyond \f[I]abs_timeout\f[] to obtain the lock before returning. A thread may hold multiple concurrent read locks. If so, \f[B]pmemobj_rwlock_unlock\f[]() must be called once for each lock obtained. The results of acquiring a read lock while the calling thread holds a write lock are undefined. .PP The \f[B]pmemobj_rwlock_wrlock\f[]() function blocks until a write lock can be acquired against read/write lock \f[I]rwlockp\f[]. If this is the first use of the lock since the opening of the pool \f[I]pop\f[], the lock is automatically reinitialized and then acquired. .PP \f[B]pmemobj_rwlock_timedwrlock\f[]() performs the same action, but will not wait beyond \f[I]abs_timeout\f[] to obtain the lock before returning. .PP The \f[B]pmemobj_rwlock_tryrdlock\f[]() function performs the same action as \f[B]pmemobj_rwlock_rdlock\f[](), but does not block if the lock cannot be immediately obtained. The results are undefined if the calling thread already holds the lock at the time the call is made. .PP The \f[B]pmemobj_rwlock_trywrlock\f[]() function performs the same action as \f[B]pmemobj_rwlock_wrlock\f[](), but does not block if the lock cannot be immediately obtained. The results are undefined if the calling thread already holds the lock at the time the call is made. .PP The \f[B]pmemobj_rwlock_unlock\f[]() function is used to release the read/write lock previously obtained by \f[B]pmemobj_rwlock_rdlock\f[](), \f[B]pmemobj_rwlock_wrlock\f[](), \f[B]pthread_rwlock_tryrdlock\f[](), or \f[B]pmemobj_rwlock_trywrlock\f[](). .PP The \f[B]pmemobj_cond_zero\f[]() function explicitly initializes the pmem\-aware condition variable \f[I]condp\f[] by zeroing it. Initialization is not necessary if the object containing the condition variable has been allocated using \f[B]pmemobj_zalloc\f[](3) or \f[B]pmemobj_tx_zalloc\f[](3). .PP The difference between \f[B]pmemobj_cond_broadcast\f[]() and \f[B]pmemobj_cond_signal\f[]() is that the former unblocks all threads waiting for the condition variable, whereas the latter blocks only one waiting thread. If no threads are waiting on \f[I]condp\f[], neither function has any effect. If more than one thread is blocked on a condition variable, the used scheduling policy determines the order in which threads are unblocked. The same mutex used for waiting must be held while calling either function. Although neither function strictly enforces this requirement, undefined behavior may follow if the mutex is not held. .PP The \f[B]pmemobj_cond_timedwait\f[]() and \f[B]pmemobj_cond_wait\f[]() functions block on a condition variable. They must be called with mutex \f[I]mutexp\f[] locked by the calling thread, or undefined behavior results. These functions atomically release mutex \f[I]mutexp\f[] and cause the calling thread to block on the condition variable \f[I]condp\f[]; atomically here means \[lq]atomically with respect to access by another thread to the mutex and then the condition variable\[rq]. That is, if another thread is able to acquire the mutex after the about\-to\-block thread has released it, then a subsequent call to \f[B]pmemobj_cond_broadcast\f[]() or \f[B]pmemobj_cond_signal\f[]() in that thread will behave as if it were issued after the about\-to\-block thread has blocked. Upon successful return, the mutex will be locked and owned by the calling thread. .SH RETURN VALUE .PP The \f[B]pmemobj_mutex_zero\f[](), \f[B]pmemobj_rwlock_zero\f[]() and \f[B]pmemobj_cond_zero\f[]() functions return no value. .PP Other locking functions return 0 on success. Otherwise, an error number will be returned to indicate the error. .SH SEE ALSO .PP \f[B]pmemobj_tx_zalloc\f[](3), \f[B]pmemobj_zalloc\f[](3), \f[B]pthread_cond_init\f[](3), \f[B]pthread_mutex_init\f[](3), \f[B]pthread_rwlock_init\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_next.3000066400000000000000000000000241331545616200177300ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pmemobj_oid.3000066400000000000000000000000221331545616200175230ustar00rootroot00000000000000.so oid_is_null.3 pmdk-1.4.1/doc/generated/pmemobj_open.3000066400000000000000000000215671331545616200177320ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_OPEN" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_open\f[](), \f[B]pmemobj_create\f[](), \f[B]pmemobj_close\f[](), \f[B]pmemobj_check\f[]() \[en] create, open, close and validate persistent memory transactional object store .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMobjpool\ *pmemobj_open(const\ char\ *path,\ const\ char\ *layout); PMEMobjpool\ *pmemobj_create(const\ char\ *path,\ const\ char\ *layout, \ \ \ \ size_t\ poolsize,\ mode_t\ mode); void\ pmemobj_close(PMEMobjpool\ *pop); int\ pmemobj_check(const\ char\ *path,\ const\ char\ *layout); \f[] .fi .SH DESCRIPTION .PP To use the pmem\-resident transactional object store provided by \f[B]libpmemobj\f[](7), a \f[I]memory pool\f[] must first be created with the \f[B]pmemobj_create\f[]() function described below. Existing pools may be opened with the \f[B]pmemobj_open\f[]() function. .PP None of the three functions described below is thread\-safe with respect to any other \f[B]libpmemobj\f[](7) functions. In other words, when creating, opening or deleting a pool, nothing else in the library can happen in parallel, and therefore these functions should be called from the main thread. .PP Once created, the memory pool is represented by an opaque handle, of type \f[I]PMEMobjpool*\f[], which is passed to most of the other \f[B]libpmemobj\f[](7) functions. Internally, \f[B]libpmemobj\f[](7) will use either \f[B]pmem_persist\f[](3) or \f[B]msync\f[](2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the \f[B]pmem_is_pmem\f[](3) function in \f[B]libpmem\f[](7) for more information). There is no need for applications to flush changes directly when using the object memory API provided by \f[B]libpmemobj\f[](7). .PP The \f[B]pmemobj_create\f[]() function creates a transactional object store with the given total \f[I]poolsize\f[]. \f[I]path\f[] specifies the name of the memory pool file to be created. \f[I]layout\f[] specifies the application's layout type in the form of a string. The layout name is not interpreted by \f[B]libpmemobj\f[](7), but may be used as a check when \f[B]pmemobj_open\f[]() is called. The layout name, including the terminating null byte (`\\0'), cannot be longer than \f[B]PMEMOBJ_MAX_LAYOUT\f[] as defined in \f[B]\f[]. A NULL \f[I]layout\f[] is equivalent to using an empty string as a layout name. \f[I]mode\f[] specifies the permissions to use when creating the file, as described by \f[B]creat\f[](2). The memory pool file is fully allocated to the size \f[I]poolsize\f[] using \f[B]posix_fallocate\f[](3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling \f[B]pmemobj_create\f[](), and then specifying \f[I]poolsize\f[] as zero. In this case \f[B]pmemobj_create\f[]() will take the pool size from the size of the existing file and will verify that the file appears to be empty by searching for any non\-zero data in the pool header at the beginning of the file. The minimum net pool size allowed by the library for a local transactional object store is defined in \f[B]\f[] as \f[B]PMEMOBJ_MIN_POOL\f[]. For remote replicas the minimum file size is defined in \f[B]\f[] as \f[B]RPMEM_MIN_PART\f[]. .PP Depending on the configuration of the system, the available non\-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemobj memory pool could be limited by the capacity of a single memory device. \f[B]libpmemobj\f[](7) allows building persistent memory resident object store spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a \f[I]pool set\f[] may be stored on a different memory device or pmem\-aware filesystem. .PP Creation of all the parts of the pool set can be done with \f[B]pmemobj_create\f[](); however, the recommended method for creating pool sets is with the \f[B]pmempool\f[](1) utility. .PP When creating a pool set consisting of multiple files, the \f[I]path\f[] argument passed to \f[B]pmemobj_create\f[]() must point to the special \f[I]set\f[] file that defines the pool layout and the location of all the parts of the pool set. The \f[I]poolsize\f[] argument must be 0. The meaning of the \f[I]layout\f[] and \f[I]mode\f[] arguments does not change, except that the same \f[I]mode\f[] is used for creation of all the parts of the pool set. .PP The \f[I]set\f[] file is a plain text file, the structure of which is described in \f[B]poolset\f[](5). .PP The \f[B]pmemobj_open\f[]() function opens an existing object store memory pool. Similar to \f[B]pmemobj_create\f[](), \f[I]path\f[] must identify either an existing obj memory pool file, or the \f[I]set\f[] file used to create a pool set. If \f[I]layout\f[] is non\-NULL, it is compared to the layout name provided to \f[B]pmemobj_create\f[]() when the pool was first created. This can be used to verify that the layout of the pool matches what was expected. The application must have permission to open the file and memory map it with read/write permissions. .PP The \f[B]pmemobj_close\f[]() function closes the memory pool indicated by \f[I]pop\f[] and deletes the memory pool handle. The object store itself lives on in the file that contains it and may be re\-opened at a later time using \f[B]pmemobj_open\f[]() as described above. .PP The \f[B]pmemobj_check\f[]() function performs a consistency check of the file indicated by \f[I]path\f[]. \f[B]pmemobj_check\f[]() opens the given \f[I]path\f[] read\-only so it never makes any changes to the file. This function is not supported on Device DAX. .SH RETURN VALUE .PP The \f[B]pmemobj_create\f[]() function returns a memory pool handle to be used with most of the functions in \f[B]libpmemobj\f[](7). On error it returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]pmemobj_open\f[]() function returns a memory pool handle to be used with most of the functions in \f[B]libpmemobj\f[](7). If an error prevents the pool from being opened, or if the given \f[I]layout\f[] does not match the pool's layout, \f[B]pmemobj_open\f[]() returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]pmemobj_close\f[]() function returns no value. .PP The \f[B]pmemobj_check\f[]() function returns 1 if the memory pool is found to be consistent. Any inconsistencies found will cause \f[B]pmemobj_check\f[]() to return 0, in which case the use of the file with \f[B]libpmemobj\f[](7) will result in undefined behavior. The debug version of \f[B]libpmemobj\f[](7) will provide additional details on inconsistencies when \f[B]PMEMOBJ_LOG_LEVEL\f[] is at least 1, asdescribed in the \f[B]DEBUGGING AND ERROR HANDLING\f[] section in \f[B]libpmemobj\f[](7). \f[B]pmemobj_check\f[]() returns \-1 and sets \f[I]errno\f[] if it cannot perform the consistency check due to other errors. .SH CAVEATS .PP Not all file systems support \f[B]posix_fallocate\f[](3). \f[B]pmemobj_create\f[]() will fail if the underlying file system does not support \f[B]posix_fallocate\f[](3). .SH SEE ALSO .PP \f[B]creat\f[](2), \f[B]msync\f[](2), \f[B]pmem_is_pmem\f[](3), \f[B]pmem_persist\f[](3), \f[B]posix_fallocate\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_persist.3000066400000000000000000000000351331545616200204450ustar00rootroot00000000000000.so pmemobj_memcpy_persist.3 pmdk-1.4.1/doc/generated/pmemobj_pool_by_oid.3000066400000000000000000000000221331545616200212460ustar00rootroot00000000000000.so oid_is_null.3 pmdk-1.4.1/doc/generated/pmemobj_pool_by_ptr.3000066400000000000000000000000221331545616200213000ustar00rootroot00000000000000.so oid_is_null.3 pmdk-1.4.1/doc/generated/pmemobj_publish.3000066400000000000000000000000261331545616200204220ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pmemobj_realloc.3000066400000000000000000000000241331545616200203730ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_reserve.3000066400000000000000000000000261331545616200204270ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pmemobj_root.3000066400000000000000000000125501331545616200177440ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_ROOT" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_root\f[](), \f[B]pmemobj_root_construct\f[]() \f[B]POBJ_ROOT\f[](), \f[B]pmemobj_root_size\f[]() \[en] root object management .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMoid\ pmemobj_root(PMEMobjpool\ *pop,\ size_t\ size); PMEMoid\ pmemobj_root_construct(PMEMobjpool\ *pop,\ size_t\ size, \ \ \ \ pmemobj_constr\ constructor,\ void\ *arg); POBJ_ROOT(PMEMobjpool\ *pop,\ TYPE) size_t\ pmemobj_root_size(PMEMobjpool\ *pop); \f[] .fi .SH DESCRIPTION .PP The root object of a persistent memory pool is an entry point for all other persistent objects allocated using the \f[B]libpmemobj\f[] API. In other words, every object stored in the persistent memory pool has the root object at the end of its reference path. It may be assumed that for each persistent memory pool the root object always exists, and there is exactly one root object in each pool. .PP The \f[B]pmemobj_root\f[]() function creates or resizes the root object for the persistent memory pool \f[I]pop\f[]. If this is the first call to \f[B]pmemobj_root\f[](), the requested \f[I]size\f[] is greater than zero and the root object does not exist, it is implicitly allocated in a thread\-safe manner, so the function may be called by more than one thread simultaneously (as long as all threads use the identical \f[I]size\f[] value). The size of the root object is guaranteed to be not less than the requested \f[I]size\f[]. If the requested size is larger than the current size, the root object is automatically resized. In such case, the old data is preserved and the extra space is zeroed. If the requested \f[I]size\f[] is equal to zero, the root object is not allocated. .PP \f[B]pmemobj_root_construct\f[]() performs the same actions as \f[B]pmemobj_root\f[](), but instead of zeroing the newly allocated object a \f[I]constructor\f[] function is called to initialize the object. The constructor is also called on reallocations. .PP The \f[B]POBJ_ROOT\f[]() macro works the same way as the \f[B]pmemobj_root\f[]() function except it returns a typed \f[I]OID\f[] value. .PP The \f[B]pmemobj_root_size\f[]() function returns the current size of the root object associated with the persistent memory pool \f[I]pop\f[]. .SH RETURN VALUE .PP Upon success, \f[B]pmemobj_root\f[]() returns a handle to the root object associated with the persistent memory pool \f[I]pop\f[]. The same root object handle is returned in all the threads. If the requested object size is larger than the maximum allocation size supported for the pool, or if there is not enough free space in the pool to satisfy a reallocation request, \f[B]pmemobj_root\f[]() returns \f[B]OID_NULL\f[] and sets \f[I]errno\f[] appropriately. If the \f[I]size\f[] was equal to zero and the root object has not been allocated, \f[B]pmemobj_root\f[]() returns \f[B]OID_NULL\f[]. .PP If the \f[B]pmemobj_root_construct\f[]() constructor fails, the allocation is canceled, \f[B]pmemobj_root_construct\f[]() returns \f[I]OID_NULL\f[], and \f[I]errno\f[] is set to \f[B]ECANCELED\f[]. \f[B]pmemobj_root_size\f[]() can be used in the constructor to check whether this is the first call to the constructor. .PP \f[B]POBJ_ROOT\f[]() returns a typed \f[I]OID\f[] of type \f[I]TYPE\f[] instead of the \f[I]PMEMoid\f[] returned by \f[B]pmemobj_root\f[](). .PP The \f[B]pmemobj_root_size\f[]() function returns the current size of the root object associated with the persistent memory pool \f[I]pop\f[]. The returned size is the largest value requested by any of the earlier \f[B]pmemobj_root\f[]() calls. If the root object has not been allocated yet, \f[B]pmemobj_root_size\f[]() returns 0. .SH SEE ALSO .PP \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_root_construct.3000066400000000000000000000000231331545616200220400ustar00rootroot00000000000000.so pmemobj_root.3 pmdk-1.4.1/doc/generated/pmemobj_root_size.3000066400000000000000000000000231331545616200207660ustar00rootroot00000000000000.so pmemobj_root.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_rdlock.3000066400000000000000000000000311331545616200216070ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_timedrdlock.3000066400000000000000000000000311331545616200226320ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_timedwrlock.3000066400000000000000000000000311331545616200226550ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_tryrdlock.3000066400000000000000000000000311331545616200223460ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_trywrlock.3000066400000000000000000000000311331545616200223710ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_unlock.3000066400000000000000000000000311331545616200216240ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_wrlock.3000066400000000000000000000000311331545616200216320ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_rwlock_zero.3000066400000000000000000000000311331545616200213100ustar00rootroot00000000000000.so pmemobj_mutex_zero.3 pmdk-1.4.1/doc/generated/pmemobj_set_funcs.3000066400000000000000000000000261331545616200207450ustar00rootroot00000000000000.so man7/libpmemobj.7 pmdk-1.4.1/doc/generated/pmemobj_set_value.3000066400000000000000000000000261331545616200207430ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pmemobj_strdup.3000066400000000000000000000000241331545616200202730ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_tx_abort.3000066400000000000000000000000271331545616200205770ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_add_range.3000066400000000000000000000216271331545616200214050ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_TX_ADD_RANGE" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_tx_add_range\f[](), \f[B]pmemobj_tx_add_range_direct\f[](), \f[B]pmemobj_tx_xadd_range\f[](), \f[B]pmemobj_tx_xadd_range_direct\f[]() .PP \f[B]TX_ADD\f[](), \f[B]TX_ADD_FIELD\f[](), \f[B]TX_ADD_DIRECT\f[](), \f[B]TX_ADD_FIELD_DIRECT\f[](), .PP \f[B]TX_XADD\f[](), \f[B]TX_XADD_FIELD\f[](), \f[B]TX_XADD_DIRECT\f[](), \f[B]TX_XADD_FIELD_DIRECT\f[](), .PP \f[B]TX_SET\f[](), \f[B]TX_SET_DIRECT\f[](), \f[B]TX_MEMCPY\f[](), \f[B]TX_MEMSET\f[]() \[en] transactional object manipulation .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmemobj_tx_add_range(PMEMoid\ oid,\ uint64_t\ off,\ size_t\ size); int\ pmemobj_tx_add_range_direct(const\ void\ *ptr,\ size_t\ size); int\ pmemobj_tx_xadd_range(PMEMoid\ oid,\ uint64_t\ off,\ size_t\ size,\ uint64_t\ flags); int\ pmemobj_tx_xadd_range_direct(const\ void\ *ptr,\ size_t\ size,\ uint64_t\ flags); TX_ADD(TOID\ o) TX_ADD_FIELD(TOID\ o,\ FIELD) TX_ADD_DIRECT(TYPE\ *p) TX_ADD_FIELD_DIRECT(TYPE\ *p,\ FIELD) TX_XADD(TOID\ o,\ uint64_t\ flags) TX_XADD_FIELD(TOID\ o,\ FIELD,\ uint64_t\ flags) TX_XADD_DIRECT(TYPE\ *p,\ uint64_t\ flags) TX_XADD_FIELD_DIRECT(TYPE\ *p,\ FIELD,\ uint64_t\ flags) TX_SET(TOID\ o,\ FIELD,\ VALUE) TX_SET_DIRECT(TYPE\ *p,\ FIELD,\ VALUE) TX_MEMCPY(void\ *dest,\ const\ void\ *src,\ size_t\ num) TX_MEMSET(void\ *dest,\ int\ c,\ size_t\ num) \f[] .fi .SH DESCRIPTION .PP \f[B]pmemobj_tx_add_range\f[]() takes a \[lq]snapshot\[rq] of the memory block of given \f[I]size\f[], located at given offset \f[I]off\f[] in the object specified by \f[I]oid\f[], and saves it to the undo log. The application is then free to directly modify the object in that memory range. In case of a failure or abort, all the changes within this range will be rolled back. The supplied block of memory has to be within the pool registered in the transaction. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_xadd_range\f[]() function behaves exactly the same as \f[B]pmemobj_tx_add_range\f[]() when \f[I]flags\f[] equals zero. \f[I]flags\f[] is a bitmask of the following values: .IP \[bu] 2 \f[B]POBJ_XADD_NO_FLUSH\f[] \- skip flush on commit when application deals with flushing or uses pmemobj_memcpy_persist) .PP \f[B]pmemobj_tx_add_range_direct\f[]() behaves the same as \f[B]pmemobj_tx_add_range\f[]() with the exception that it operates on virtual memory addresses and not persistent memory objects. It takes a \[lq]snapshot\[rq] of a persistent memory block of given \f[I]size\f[], located at the given address \f[I]ptr\f[] in the virtual memory space and saves it to the undo log. The application is then free to directly modify the object in that memory range. In case of a failure or abort, all the changes within this range will be rolled back. The supplied block of memory has to be within the pool registered in the transaction. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_xadd_range_direct\f[]() function behaves exactly the same as \f[B]pmemobj_tx_add_range_direct\f[]() when \f[I]flags\f[] equals zero. \f[I]flags\f[] is a bitmask of the following values: .IP \[bu] 2 \f[B]POBJ_XADD_NO_FLUSH\f[] \- skip flush on commit (when application deals with flushing or uses pmemobj_memcpy_persist) .PP Similarly to the macros controlling the transaction flow, \f[B]libpmemobj\f[] defines a set of macros that simplify the transactional operations on persistent objects. Note that those macros operate on typed object handles, thus eliminating the need to specify the size of the object, or the size and offset of the field in the user\-defined structure that is to be modified. .PP The \f[B]TX_ADD_FIELD\f[]() macro saves the current value of given \f[I]FIELD\f[] of the object referenced by a handle \f[I]o\f[] in the undo log. The application is then free to directly modify the specified \f[I]FIELD\f[]. In case of a failure or abort, the saved value will be restored. .PP The \f[B]TX_XADD_FIELD\f[]() macro works exactly like \f[B]TX_ADD_FIELD\f[] when \f[I]flags\f[] equals 0. The \f[I]flags\f[] argument is a bitmask of values described in \f[B]pmemobj_tx_xadd_range\f[], above. .PP The \f[B]TX_ADD\f[]() macro takes a \[lq]snapshot\[rq] of the entire object referenced by object handle \f[I]o\f[] and saves it in the undo log. The object size is determined from its \f[I]TYPE\f[]. The application is then free to directly modify the object. In case of a failure or abort, all the changes within the object will be rolled back. .PP The \f[B]TX_XADD\f[]() macro works exactly like \f[B]TX_ADD\f[] when \f[I]flags\f[] equals 0. The \f[I]flags\f[] argument is a bitmask of values as described in \f[B]pmemobj_tx_xadd_range\f[], above. .PP The \f[B]TX_ADD_FIELD_DIRECT\f[]() macro saves the current value of the given \f[I]FIELD\f[] of the object referenced by (direct) pointer \f[I]p\f[] in the undo log. The application is then free to directly modify the specified \f[I]FIELD\f[]. In case of a failure or abort, the saved value will be restored. .PP The \f[B]TX_XADD_FIELD_DIRECT\f[]() macro works exactly like \f[B]TX_ADD_FIELD_DIRECT\f[] when \f[I]flags\f[] equals 0. The \f[I]flags\f[] argument is a bitmask of values as described in \f[B]pmemobj_tx_xadd_range_direct\f[], above. .PP The \f[B]TX_ADD_DIRECT\f[]() macro takes a \[lq]snapshot\[rq] of the entire object referenced by (direct) pointer \f[I]p\f[] and saves it in the undo log. The object size is determined from its \f[I]TYPE\f[]. The application is then free to directly modify the object. In case of a failure or abort, all the changes within the object will be rolled back. .PP The \f[B]TX_XADD_DIRECT\f[]() macro works exactly like \f[B]TX_ADD_DIRECT\f[] when \f[I]flags\f[] equals 0. The \f[I]flags\f[] argument is a bitmask of values as described in \f[B]pmemobj_tx_xadd_range_direct\f[], above. .PP The \f[B]TX_SET\f[]() macro saves the current value of the given \f[I]FIELD\f[] of the object referenced by handle \f[I]o\f[] in the undo log, and then sets its new \f[I]VALUE\f[]. In case of a failure or abort, the saved value will be restored. .PP The \f[B]TX_SET_DIRECT\f[]() macro saves in the undo log the current value of given \f[I]FIELD\f[] of the object referenced by (direct) pointer \f[I]p\f[], and then set its new \f[I]VALUE\f[]. In case of a failure or abort, the saved value will be restored. .PP The \f[B]TX_MEMCPY\f[]() macro saves in the undo log the current content of \f[I]dest\f[] buffer and then overwrites the first \f[I]num\f[] bytes of its memory area with the data copied from the buffer pointed by \f[I]src\f[]. In case of a failure or abort, the saved value will be restored. .PP The \f[B]TX_MEMSET\f[]() macro saves the current content of the \f[I]dest\f[] buffer in the undo log and then fills the first \f[I]num\f[] bytes of its memory area with the constant byte \f[I]c\f[]. In case of a failure or abort, the saved value will be restored. .SH RETURN VALUE .PP On success, \f[B]pmemobj_tx_add_range\f[](), \f[B]pmemobj_tx_xadd_range\f[](), \f[B]pmemobj_tx_add_range_direct\f[]() and \f[B]pmemobj_tx_xadd_range_direct\f[]() return 0. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[] and an error number is returned. .SH SEE ALSO .PP \f[B]pmemobj_tx_alloc\f[](3), \f[B]pmemobj_tx_begin\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_tx_add_range_direct.3000066400000000000000000000000331331545616200227230ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/pmemobj_tx_alloc.3000066400000000000000000000264341331545616200205740ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_TX_ALLOC" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_tx_alloc\f[](), \f[B]pmemobj_tx_zalloc\f[](), \f[B]pmemobj_tx_xalloc\f[](), \f[B]pmemobj_tx_realloc\f[](), \f[B]pmemobj_tx_zrealloc\f[](), \f[B]pmemobj_tx_strdup\f[](), \f[B]pmemobj_tx_wcsdup\f[](), \f[B]pmemobj_tx_free\f[](), .PP \f[B]TX_NEW\f[](), \f[B]TX_ALLOC\f[](), \f[B]TX_ZNEW\f[](), \f[B]TX_ZALLOC\f[](), \f[B]TX_XALLOC\f[](), \f[B]TX_REALLOC\f[](), \f[B]TX_ZREALLOC\f[](), \f[B]TX_STRDUP\f[](), \f[B]TX_WCSDUP\f[](), \f[B]TX_FREE\f[]() \[en] transactional object manipulation .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMoid\ pmemobj_tx_alloc(size_t\ size,\ uint64_t\ type_num); PMEMoid\ pmemobj_tx_zalloc(size_t\ size,\ uint64_t\ type_num); PMEMoid\ pmemobj_tx_xalloc(size_t\ size,\ uint64_t\ type_num,\ uint64_t\ flags); PMEMoid\ pmemobj_tx_realloc(PMEMoid\ oid,\ size_t\ size,\ uint64_t\ type_num); PMEMoid\ pmemobj_tx_zrealloc(PMEMoid\ oid,\ size_t\ size,\ uint64_t\ type_num); PMEMoid\ pmemobj_tx_strdup(const\ char\ *s,\ uint64_t\ type_num); PMEMoid\ pmemobj_tx_wcsdup(const\ wchar_t\ *s,\ uint64_t\ type_num); int\ pmemobj_tx_free(PMEMoid\ oid); TX_NEW(TYPE) TX_ALLOC(TYPE,\ size_t\ size) TX_ZNEW(TYPE) TX_ZALLOC(TYPE,\ size_t\ size) TX_XALLOC(TYPE,\ size_t\ size,\ uint64_t\ flags) TX_REALLOC(TOID\ o,\ size_t\ size) TX_ZREALLOC(TOID\ o,\ size_t\ size) TX_STRDUP(const\ char\ *s,\ uint64_t\ type_num) TX_WCSDUP(const\ wchar_t\ *s,\ uint64_t\ type_num) TX_FREE(TOID\ o) \f[] .fi .SH DESCRIPTION .PP The \f[B]pmemobj_tx_alloc\f[]() function transactionally allocates a new object of given \f[I]size\f[] and \f[I]type_num\f[]. In contrast to the non\-transactional allocations, the objects are added to the internal object containers of given \f[I]type_num\f[] only after the transaction is committed, making the objects visible to the \f[B]POBJ_FOREACH_*\f[]() macros. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_zalloc\f[]() function transactionally allocates a new zeroed object of given \f[I]size\f[] and \f[I]type_num\f[]. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_xalloc\f[]() function transactionally allocates a new object of given \f[I]size\f[] and \f[I]type_num\f[]. The \f[I]flags\f[] argument is a bitmask of the following values: .IP \[bu] 2 \f[B]POBJ_XALLOC_ZERO\f[] \- zero the object (equivalent of pmemobj_tx_zalloc) .IP \[bu] 2 \f[B]POBJ_XALLOC_NO_FLUSH\f[] \- skip flush on commit (when application deals with flushing or uses pmemobj_memcpy_persist) .IP \[bu] 2 \f[B]POBJ_CLASS_ID(class_id)\f[] \- allocate the object from the allocation class with id equal to \f[I]class_id\f[] .PP This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_realloc\f[]() function transactionally resizes an existing object to the given \f[I]size\f[] and changes its type to \f[I]type_num\f[]. If \f[I]oid\f[] is \f[B]OID_NULL\f[], then the call is equivalent to \f[I]pmemobj_tx_alloc(pop, size, type_num)\f[]. If \f[I]size\f[] is equal to zero and \f[I]oid\f[] is not \f[B]OID_NULL\f[], then the call is equivalent to \f[I]pmemobj_tx_free(oid)\f[]. If the new size is larger than the old size, the added memory will \f[I]not\f[] be initialized. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_zrealloc\f[]() function transactionally resizes an existing object to the given \f[I]size\f[] and changes its type to \f[I]type_num\f[]. If the new size is larger than the old size, the extended new space is zeroed. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_strdup\f[]() function transactionally allocates a new object containing a duplicate of the string \f[I]s\f[] and assigns it a type \f[I]type_num\f[]. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_wcsdup\f[]() function transactionally allocates a new object containing a duplicate of the wide character string \f[I]s\f[] and assigns it a type \f[I]type_num\f[]. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_free\f[]() function transactionally frees an existing object referenced by \f[I]oid\f[]. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]TX_NEW\f[]() macro transactionally allocates a new object of given \f[I]TYPE\f[] and assigns it a type number read from the typed \f[I]OID\f[]. The allocation size is determined from the size of the user\-defined structure \f[I]TYPE\f[]. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the newly allocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_ALLOC\f[]() macro transactionally allocates a new object of given \f[I]TYPE\f[] and assigns it a type number read from the typed \f[I]OID\f[]. The allocation size is passed by \f[I]size\f[] parameter. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the newly allocated object. Otherwise, the stage is set to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_ZNEW\f[]() macro transactionally allocates a new zeroed object of given \f[I]TYPE\f[] and assigns it a type number read from the typed \f[I]OID\f[]. The allocation size is determined from the size of the user\-defined structure \f[I]TYPE\f[]. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the newly allocated object. Otherwise, stage changes to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_ZALLOC\f[]() macro transactionally allocates a new zeroed object of given \f[I]TYPE\f[] and assigns it a type number read from the typed \f[I]OID\f[]. The allocation size is passed by \f[I]size\f[] argument. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the newly allocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_XALLOC\f[]() macro transactionally allocates a new object of given \f[I]TYPE\f[] and assigns it a type number read from the typed \f[I]OID\f[]. The allocation size is passed by \f[I]size\f[] argument. The \f[I]flags\f[] argument is a bitmask of values described in \f[B]pmemobj_tx_xalloc\f[] section. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the newly allocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_REALLOC\f[]() macro transactionally resizes an existing object referenced by a handle \f[I]o\f[] to the given \f[I]size\f[]. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the reallocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_ZREALLOC\f[]() macro transactionally resizes an existing object referenced by a handle \f[I]o\f[] to the given \f[I]size\f[]. If the new size is larger than the old size, the extended new space is zeroed. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the reallocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_STRDUP\f[]() macro transactionally allocates a new object containing a duplicate of the string \f[I]s\f[] and assigns it type \f[I]type_num\f[]. If successful and called during \f[B]TX_STAGE_WORK\f[] it returns a handle to the newly allocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_WCSDUP\f[]() macro transactionally allocates a new object containing a duplicate of the wide character string \f[I]s\f[] and assigns it a type \f[I]type_num\f[]. If successful and called during \f[B]TX_STAGE_WORK\f[], it returns a handle to the newly allocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. .PP The \f[B]TX_FREE\f[]() macro transactionally frees the memory space represented by an object handle \f[I]o\f[]. If \f[I]o\f[] is \f[B]OID_NULL\f[], no operation is performed. If successful and called during \f[B]TX_STAGE_WORK\f[], \f[B]TX_FREE\f[]() returns 0. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[] and an error number is returned. .SH RETURN VALUE .PP On success, the \f[B]pmemobj_tx_alloc\f[]() ,\f[B]pmemobj_tx_zalloc\f[](), \f[B]pmemobj_tx_xalloc\f[](), \f[B]pmemobj_tx_strdup\f[]() and \f[B]pmemobj_tx_wcsdup\f[]() functions return a handle to the newly allocated object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. If \f[I]size\f[] equals 0, \f[B]OID_NULL\f[] is returned and \f[I]errno\f[] is set appropriately. .PP On success, \f[B]pmemobj_tx_realloc\f[]() and \f[B]pmemobj_tx_zrealloc\f[]() return a handle to the resized object. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[], \f[B]OID_NULL\f[] is returned, and \f[I]errno\f[] is set appropriately. Note that the object handle value may change as a result of reallocation. .PP On success, \f[B]pmemobj_tx_free\f[]() returns 0. Otherwise, the stage is set to \f[B]TX_STAGE_ONABORT\f[] and an error number is returned. .SH SEE ALSO .PP \f[B]pmemobj_tx_add_range\f[](3), **pmemobj_tx_begin*(3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_tx_begin.3000066400000000000000000000454671331545616200205750ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMOBJ_TX_BEGIN" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmemobj_tx_stage\f[](), .PP \f[B]pmemobj_tx_begin\f[](), \f[B]pmemobj_tx_lock\f[](), \f[B]pmemobj_tx_abort\f[](), \f[B]pmemobj_tx_commit\f[](), \f[B]pmemobj_tx_end\f[](), \f[B]pmemobj_tx_errno\f[](), \f[B]pmemobj_tx_process\f[](), .PP \f[B]TX_BEGIN_PARAM\f[](), \f[B]TX_BEGIN_CB\f[](), \f[B]TX_BEGIN\f[](), \f[B]TX_ONABORT\f[], \f[B]TX_ONCOMMIT\f[], \f[B]TX_FINALLY\f[], \f[B]TX_END\f[] \[en] transactional object manipulation .SH SYNOPSIS .IP .nf \f[C] #include\ enum\ tx_stage\ pmemobj_tx_stage(void); int\ pmemobj_tx_begin(PMEMobjpool\ *pop,\ jmp_buf\ *env,\ enum\ pobj_tx_param,\ ...); int\ pmemobj_tx_lock(enum\ tx_lock\ lock_type,\ void\ *lockp); void\ pmemobj_tx_abort(int\ errnum); void\ pmemobj_tx_commit(void); int\ pmemobj_tx_end(void); int\ pmemobj_tx_errno(void); void\ pmemobj_tx_process(void); TX_BEGIN_PARAM(PMEMobjpool\ *pop,\ ...) TX_BEGIN_CB(PMEMobjpool\ *pop,\ cb,\ arg,\ ...) TX_BEGIN(PMEMobjpool\ *pop) TX_ONABORT TX_ONCOMMIT TX_FINALLY TX_END \f[] .fi .SH DESCRIPTION .PP The non\-transactional functions and macros described in \f[B]pmemobj_alloc\f[](3), \f[B]pmemobj_list_insert\f[](3) and \f[B]POBJ_LIST_HEAD\f[](3) only guarantee the atomicity of a single operation on an object. In case of more complex changes involving multiple operations on an object, or allocation and modification of multiple objects, data consistency and fail\-safety may be provided only by using \f[I]atomic transactions\f[]. .PP A transaction is defined as series of operations on persistent memory objects that either all occur, or nothing occurs. In particular, if the execution of a transaction is interrupted by a power failure or a system crash, it is guaranteed that after system restart, all the changes made as a part of the uncompleted transaction will be rolled back, restoring the consistent state of the memory pool from the moment when the transaction was started. .PP Note that transactions do not provide atomicity with respect to other threads. All the modifications performed within the transactions are immediately visible to other threads. Therefore it is the responsibility of the application to implement a proper thread synchronization mechanism. .PP Each thread may have only one transaction open at a time, but that transaction may be nested. Nested transactions are flattened. Committing the nested transaction does not commit the outer transaction; however, errors in the nested transaction are propagated up to the outermost level, resulting in the interruption of the entire transaction. .PP Each transaction is visible only for the thread that started it. No other threads can add operations, commit or abort the transaction initiated by another thread. Multiple threads may have transactions open on a given memory pool at the same time. .PP Please see the \f[B]CAVEATS\f[] section below for known limitations of the transactional API. .PP The \f[B]pmemobj_tx_stage\f[]() function returns the current \f[I]transaction stage\f[] for a thread. Stages are changed only by the \f[B]pmemobj_tx_*\f[]() functions. Transaction stages are defined as follows: .IP \[bu] 2 \f[B]TX_STAGE_NONE\f[] \- no open transaction in this thread .IP \[bu] 2 \f[B]TX_STAGE_WORK\f[] \- transaction in progress .IP \[bu] 2 \f[B]TX_STAGE_ONCOMMIT\f[] \- successfully committed .IP \[bu] 2 \f[B]TX_STAGE_ONABORT\f[] \- starting the transaction failed or transaction aborted .IP \[bu] 2 \f[B]TX_STAGE_FINALLY\f[] \- ready for clean up .PP The \f[B]pmemobj_tx_begin\f[]() function starts a new transaction in the current thread. If called within an open transaction, it starts a nested transaction. The caller may use the \f[I]env\f[] argument to provide a pointer to a calling environment to be restored in case of transaction abort. This information must be provided by the caller using the \f[B]setjmp\f[](3) macro. .PP A new transaction may be started only if the current stage is \f[B]TX_STAGE_NONE\f[] or \f[B]TX_STAGE_WORK\f[]. If successful, the \f[I]transaction stage\f[] changes to \f[B]TX_STAGE_WORK\f[]. Otherwise, the stage is changed to \f[B]TX_STAGE_ONABORT\f[]. .PP Optionally, a list of parameters for the transaction may be provided. Each parameter consists of a type followed by a type\-specific number of values. Currently there are 4 types: .IP \[bu] 2 \f[B]TX_PARAM_NONE\f[], used as a termination marker. No following value. .IP \[bu] 2 \f[B]TX_PARAM_MUTEX\f[], followed by one value, a pmem\-resident PMEMmutex .IP \[bu] 2 \f[B]TX_PARAM_RWLOCK\f[], followed by one value, a pmem\-resident PMEMrwlock .IP \[bu] 2 \f[B]TX_PARAM_CB\f[], followed by two values: a callback function of type \f[I]pmemobj_tx_callback\f[], and a void pointer .PP Using \f[B]TX_PARAM_MUTEX\f[] or \f[B]TX_PARAM_RWLOCK\f[] causes the specified lock to be acquired at the beginning of the transaction. \f[B]TX_PARAM_RWLOCK\f[] acquires the lock for writing. It is guaranteed that \f[B]pmemobj_tx_begin\f[]() will acquire all locks prior to successful completion, and they will be held by the current thread until the outermost transaction is finished. Locks are taken in order from left to right. To avoid deadlocks, the user is responsible for proper lock ordering. .PP \f[B]TX_PARAM_CB\f[] registers the specified callback function to be executed at each transaction stage. For \f[B]TX_STAGE_WORK\f[], the callback is executed prior to commit. For all other stages, the callback is executed as the first operation after a stage change. It will also be called after each transaction; in this case the \f[I]stage\f[] parameter will be set to \f[B]TX_STAGE_NONE\f[]. \f[I]pmemobj_tx_callback\f[] must be compatible with: .PP \f[C]void\ func(PMEMobjpool\ *pop,\ enum\ pobj_tx_stage\ stage,\ void\ *arg)\f[] .PP \f[I]pop\f[] is a pool identifier used in \f[B]pmemobj_tx_begin\f[](), \f[I]stage\f[] is a current transaction stage and \f[I]arg\f[] is the second parameter of \f[B]TX_PARAM_CB\f[]. Without considering transaction nesting, this mechanism can be considered an alternative method for executing code between stages (instead of \f[B]TX_ONCOMMIT\f[], \f[B]TX_ONABORT\f[], etc). However, there are 2 significant differences when nested transactions are used: .IP \[bu] 2 The registered function is executed only in the outermost transaction, even if registered in an inner transaction. .IP \[bu] 2 There can be only one callback in the entire transaction, that is, the callback cannot be changed in an inner transaction. .PP Note that \f[B]TX_PARAM_CB\f[] does not replace the \f[B]TX_ONCOMMIT\f[], \f[B]TX_ONABORT\f[], etc. macros. They can be used together: the callback will be executed \f[I]before\f[] a \f[B]TX_ONCOMMIT\f[], \f[B]TX_ONABORT\f[], etc. section. .PP \f[B]TX_PARAM_CB\f[] can be used when the code dealing with transaction stage changes is shared between multiple users or when it must be executed only in the outer transaction. For example it can be very useful when the application must synchronize persistent and transient state. .PP The \f[B]pmemobj_tx_lock\f[]() function acquires the lock \f[I]lockp\f[] of type \f[I]lock_type\f[] and adds it to the current transaction. \f[I]lock_type\f[] may be \f[B]TX_LOCK_MUTEX\f[] or \f[B]TX_LOCK_RWLOCK\f[]; \f[I]lockp\f[] must be of type \f[I]PMEMmutex\f[] or \f[I]PMEMrwlock\f[], respectively. If \f[I]lock_type\f[] is \f[B]TX_LOCK_RWLOCK\f[] the lock is acquired for writing. If the lock is not successfully acquired, the stage is changed to \f[B]TX_STAGE_ONABORT\f[]. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP \f[B]pmemobj_tx_abort\f[]() aborts the current transaction and causes a transition to \f[B]TX_STAGE_ONABORT\f[]. If \f[I]errnum\f[] is equal to 0, the transaction error code is set to \f[B]ECANCELED\f[]; otherwise, it is set to \f[I]errnum\f[]. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_commit\f[]() function commits the current open transaction and causes a transition to \f[B]TX_STAGE_ONCOMMIT\f[]. If called in the context of the outermost transaction, all the changes may be considered as durably written upon successful completion. This function must be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_end\f[]() function performs a cleanup of the current transaction. If called in the context of the outermost transaction, it releases all the locks acquired by \f[B]pmemobj_tx_begin\f[]() for outer and nested transactions. If called in the context of a nested transaction, it returns to the context of the outer transaction in \f[B]TX_STAGE_WORK\f[], without releasing any locks. The \f[B]pmemobj_tx_end\f[]() function can be called during \f[B]TX_STAGE_NONE\f[] if transitioned to this stage using \f[B]pmemobj_tx_process\f[](). If not already in \f[B]TX_STAGE_NONE\f[], it causes the transition to \f[B]TX_STAGE_NONE\f[]. \f[B]pmemobj_tx_end\f[] must always be called for each \f[B]pmemobj_tx_begin\f[](), even if starting the transaction failed. This function must \f[I]not\f[] be called during \f[B]TX_STAGE_WORK\f[]. .PP The \f[B]pmemobj_tx_errno\f[]() function returns the error code of the last transaction. .PP The \f[B]pmemobj_tx_process\f[]() function performs the actions associated with the current stage of the transaction, and makes the transition to the next stage. It must be called in a transaction. The current stage must always be obtained by a call to \f[B]pmemobj_tx_stage\f[](). \f[B]pmemobj_tx_process\f[]() performs the following transitions in the transaction stage flow: .IP \[bu] 2 \f[B]TX_STAGE_WORK\f[] \-> \f[B]TX_STAGE_ONCOMMIT\f[] .IP \[bu] 2 \f[B]TX_STAGE_ONABORT\f[] \-> \f[B]TX_STAGE_FINALLY\f[] .IP \[bu] 2 \f[B]TX_STAGE_ONCOMMIT\f[] \-> \f[B]TX_STAGE_FINALLY\f[] .IP \[bu] 2 \f[B]TX_STAGE_FINALLY\f[] \-> \f[B]TX_STAGE_NONE\f[] .IP \[bu] 2 \f[B]TX_STAGE_NONE\f[] \-> \f[B]TX_STAGE_NONE\f[] .PP \f[B]pmemobj_tx_process\f[]() must not be called after calling \f[B]pmemobj_tx_end\f[]() for the outermost transaction. .PP In addition to the above API, \f[B]libpmemobj\f[](7) offers a more intuitive method of building transactions using the set of macros described below. When using these macros, the complete transaction flow looks like this: .IP .nf \f[C] TX_BEGIN(Pop)\ { \ \ \ \ /*\ the\ actual\ transaction\ code\ goes\ here...\ */ }\ TX_ONCOMMIT\ { \ \ \ \ /* \ \ \ \ \ *\ optional\ \-\ executed\ only\ if\ the\ above\ block \ \ \ \ \ *\ successfully\ completes \ \ \ \ \ */ }\ TX_ONABORT\ { \ \ \ \ /* \ \ \ \ \ *\ optional\ \-\ executed\ only\ if\ starting\ the\ transaction\ fails, \ \ \ \ \ *\ or\ if\ transaction\ is\ aborted\ by\ an\ error\ or\ a\ call\ to \ \ \ \ \ *\ pmemobj_tx_abort() \ \ \ \ \ */ }\ TX_FINALLY\ { \ \ \ \ /* \ \ \ \ \ *\ optional\ \-\ if\ exists,\ it\ is\ executed\ after \ \ \ \ \ *\ TX_ONCOMMIT\ or\ TX_ONABORT\ block \ \ \ \ \ */ }\ TX_END\ /*\ mandatory\ */ \f[] .fi .IP .nf \f[C] TX_BEGIN_PARAM(PMEMobjpool\ *pop,\ ...) TX_BEGIN_CB(PMEMobjpool\ *pop,\ cb,\ arg,\ ...) TX_BEGIN(PMEMobjpool\ *pop) \f[] .fi .PP The \f[B]TX_BEGIN_PARAM\f[](), \f[B]TX_BEGIN_CB\f[]() and \f[B]TX_BEGIN\f[]() macros start a new transaction in the same way as \f[B]pmemobj_tx_begin\f[](), except that instead of the environment buffer provided by a caller, they set up the local \f[I]jmp_buf\f[] buffer and use it to catch the transaction abort. The \f[B]TX_BEGIN\f[]() macro starts a transaction without any options. \f[B]TX_BEGIN_PARAM\f[] may be used when there is a need to acquire locks prior to starting a transaction (such as for a multi\-threaded program) or set up a transaction stage callback. \f[B]TX_BEGIN_CB\f[] is just a wrapper around \f[B]TX_BEGIN_PARAM\f[] that validates the callback signature. (For compatibility there is also a \f[B]TX_BEGIN_LOCK\f[] macro, which is an alias for \f[B]TX_BEGIN_PARAM\f[]). Each of these macros must be followed by a block of code with all the operations that are to be performed atomically. .PP The \f[B]TX_ONABORT\f[] macro starts a block of code that will be executed only if starting the transaction fails due to an error in \f[B]pmemobj_tx_begin\f[](), or if the transaction is aborted. This block is optional, but in practice it should not be omitted. If it is desirable to crash the application when a transaction aborts and there is no \f[B]TX_ONABORT\f[] section, the application can define the \f[B]POBJ_TX_CRASH_ON_NO_ONABORT\f[] macro before inclusion of \f[B]\f[]. This provides a default \f[B]TX_ONABORT\f[] section which just calls \f[B]abort\f[](3). .PP The \f[B]TX_ONCOMMIT\f[] macro starts a block of code that will be executed only if the transaction is successfully committed, which means that the execution of code in the \f[B]TX_BEGIN\f[]() block has not been interrupted by an error or by a call to \f[B]pmemobj_tx_abort\f[](). This block is optional. .PP The \f[B]TX_FINALLY\f[] macro starts a block of code that will be executed regardless of whether the transaction is committed or aborted. This block is optional. .PP The \f[B]TX_END\f[] macro cleans up and closes the transaction started by the \f[B]TX_BEGIN\f[]() / \f[B]TX_BEGIN_PARAM\f[]() / \f[B]TX_BEGIN_CB\f[]() macros. It is mandatory to terminate each transaction with this macro. If the transaction was aborted, \f[I]errno\f[] is set appropriately. .SH RETURN VALUE .PP The \f[B]pmemobj_tx_stage\f[]() function returns the stage of the current transaction stage for a thread. .PP On success, \f[B]pmemobj_tx_begin\f[]() returns 0. Otherwise, an error number is returned. .PP The \f[B]pmemobj_tx_begin\f[]() and \f[B]pmemobj_tx_lock\f[]() functions return zero if \f[I]lockp\f[] is successfully added to the transaction. Otherwise, an error number is returned. .PP The \f[B]pmemobj_tx_abort\f[]() and \f[B]pmemobj_tx_commit\f[]() functions return no value. .PP The \f[B]pmemobj_tx_end\f[]() function returns 0 if the transaction was successful. Otherwise it returns the error code set by \f[B]pmemobj_tx_abort\f[](). Note that \f[B]pmemobj_tx_abort\f[]() can be called internally by the library. .PP The \f[B]pmemobj_tx_errno\f[]() function returns the error code of the last transaction. .PP The \f[B]pmemobj_tx_process\f[]() function returns no value. .SH CAVEATS .PP Transaction flow control is governed by the \f[B]setjmp\f[](3) and \f[B]longjmp\f[](3) macros, and they are used in both the macro and function flavors of the API. The transaction will longjmp on transaction abort. This has one major drawback, which is described in the ISO C standard subsection 7.13.2.1. It says that \f[B]the values of objects of automatic storage duration that are local to the function containing the setjmp invocation that do not have volatile\-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate.\f[] .PP The following example illustrates the issue described above. .IP .nf \f[C] int\ *bad_example_1\ =\ (int\ *)0xBAADF00D; int\ *bad_example_2\ =\ (int\ *)0xBAADF00D; int\ *bad_example_3\ =\ (int\ *)0xBAADF00D; int\ *\ volatile\ good_example\ =\ (int\ *)0xBAADF00D; TX_BEGIN(pop)\ { \ \ \ \ bad_example_1\ =\ malloc(sizeof(int)); \ \ \ \ bad_example_2\ =\ malloc(sizeof(int)); \ \ \ \ bad_example_3\ =\ malloc(sizeof(int)); \ \ \ \ good_example\ =\ malloc(sizeof(int)); \ \ \ \ /*\ manual\ or\ library\ abort\ called\ here\ */ \ \ \ \ pmemobj_tx_abort(EINVAL); }\ TX_ONCOMMIT\ { \ \ \ \ /* \ \ \ \ \ *\ This\ section\ is\ longjmp\-safe \ \ \ \ \ */ }\ TX_ONABORT\ { \ \ \ \ /* \ \ \ \ \ *\ This\ section\ is\ not\ longjmp\-safe \ \ \ \ \ */ \ \ \ \ free(good_example);\ /*\ OK\ */ \ \ \ \ free(bad_example_1);\ /*\ undefined\ behavior\ */ }\ TX_FINALLY\ { \ \ \ \ /* \ \ \ \ \ *\ This\ section\ is\ not\ longjmp\-safe\ on\ transaction\ abort\ only \ \ \ \ \ */ \ \ \ \ free(bad_example_2);\ /*\ undefined\ behavior\ */ }\ TX_END free(bad_example_3);\ /*\ undefined\ behavior\ */ \f[] .fi .PP Objects which are not volatile\-qualified, are of automatic storage duration and have been changed between the invocations of \f[B]setjmp\f[](3) and \f[B]longjmp\f[](3) (that also means within the work section of the transaction after \f[B]TX_BEGIN\f[]()) should not be used after a transaction abort, or should be used with utmost care. This also includes code after the \f[B]TX_END\f[] macro. .PP \f[B]libpmemobj\f[](7) is not cancellation\-safe. The pool will never be corrupted because of a canceled thread, but other threads may stall waiting on locks taken by that thread. If the application wants to use \f[B]pthread_cancel\f[](3), it must disable cancellation before calling any \f[B]libpmemobj\f[](7) APIs (see \f[B]pthread_setcancelstate\f[](3) with \f[B]PTHREAD_CANCEL_DISABLE\f[]), and re\-enable it afterwards. Deferring cancellation (\f[B]pthread_setcanceltype\f[](3) with \f[B]PTHREAD_CANCEL_DEFERRED\f[]) is not safe enough, because \f[B]libpmemobj\f[](7) internally may call functions that are specified as cancellation points in POSIX. .PP \f[B]libpmemobj\f[](7) relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. \f[B]dlclose\f[](3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. .SH SEE ALSO .PP \f[B]dlclose\f[](3), \f[B]longjmp\f[](3), \f[B]pmemobj_tx_add_range\f[](3), \f[B]pmemobj_tx_alloc\f[](3), \f[B]pthread_setcancelstate\f[](3), \f[B]pthread_setcanceltype\f[](3), \f[B]setjmp\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmemobj_tx_commit.3000066400000000000000000000000271331545616200207600ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_end.3000066400000000000000000000000271331545616200202360ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_errno.3000066400000000000000000000000271331545616200206150ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_free.3000066400000000000000000000000271331545616200204110ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_tx_lock.3000066400000000000000000000000271331545616200204200ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_process.3000066400000000000000000000000271331545616200211460ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_publish.3000066400000000000000000000000261331545616200211350ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pmemobj_tx_realloc.3000066400000000000000000000000271331545616200211110ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_tx_stage.3000066400000000000000000000000271331545616200205730ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_strdup.3000066400000000000000000000000271331545616200210110ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_tx_wcsdup.3000066400000000000000000000000271331545616200207750ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_tx_xadd_range.3000066400000000000000000000000331331545616200215610ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/pmemobj_tx_xadd_range_direct.3000066400000000000000000000000331331545616200231130ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/pmemobj_tx_xalloc.3000066400000000000000000000000271331545616200207520ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/pmemobj_tx_zalloc.3000066400000000000000000000000271331545616200207540ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_tx_zrealloc.3000066400000000000000000000000271331545616200213030ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_type_num.3000066400000000000000000000000221331545616200206100ustar00rootroot00000000000000.so oid_is_null.3 pmdk-1.4.1/doc/generated/pmemobj_wcsdup.3000066400000000000000000000000241331545616200202570ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_xalloc.3000066400000000000000000000000241331545616200202340ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_xreserve.3000066400000000000000000000000261331545616200206170ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pmemobj_zalloc.3000066400000000000000000000000241331545616200202360ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmemobj_zrealloc.3000066400000000000000000000000241331545616200205650ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pmempool-check.1000066400000000000000000000102501331545616200201440ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-CHECK" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-check\f[] \[en] check and repair persistent memory pool .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ check\ []\ \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool\f[] invoked with \f[I]check\f[] command checks consistency of a given pool file. If the pool file is consistent \f[B]pmempool\f[] exits with 0 value. If the pool file is not consistent non\-zero error code is returned. .PP In case of any errors, the proper message is printed. The verbosity level may be increased using \f[B]\-v\f[] option. The output messages may be also suppressed using \f[B]\-q\f[] option. .PP It is possible to try to fix encountered problems using \f[B]\-r\f[] option. In order to be sure this will not corrupt your data you can either create backup of the pool file using \f[B]\-b\f[] option or just print what would be fixed without modifying original pool using \f[B]\-N\f[] option. .RS .PP NOTE: Currently, checking the consistency of a \f[I]pmemobj\f[] pool is \f[B]not\f[] supported. .RE .SS Available options: .PP \f[C]\-r,\ \-\-repair\f[] .PP Try to repair a pool file if possible. .PP \f[C]\-y,\ \-\-yes\f[] .PP Answer yes on all questions. .PP \f[C]\-N,\ \-\-no\-exec\f[] .PP Don't execute, just show what would be done. Not supported on Device DAX. .PP \f[C]\-b,\ \-\-backup\ \f[] .PP Create backup of a pool file before executing. Terminate if it is \f[I]not\f[] possible to create a backup file. This option requires \f[B]\-r\f[] option. .PP \f[C]\-a,\ \-\-advanced\f[] .PP Perform advanced repairs. This option enables more aggressive steps in attempts to repair a pool. This option requires \f[C]\-r,\ \-\-repair\f[]. .PP \f[C]\-q,\ \-\-quiet\f[] .PP Be quiet and don't print any messages. .PP \f[C]\-v,\ \-\-verbose\f[] .PP Be more verbose. .PP \f[C]\-h,\ \-\-help\f[] .PP Display help message and exit. .SH EXAMPLE .IP .nf \f[C] $\ pmempool\ check\ pool.bin \f[] .fi .PP Check consistency of \[lq]pool.bin\[rq] pool file .IP .nf \f[C] $\ pmempool\ check\ \-\-repair\ \-\-backup\ pool.bin.backup\ pool.bin \f[] .fi .PP Check consistency of \[lq]pool.bin\[rq] pool file, create backup and repair if necessary. .IP .nf \f[C] $\ pmempool\ check\ \-rvN\ pool.bin \f[] .fi .PP Check consistency of \[lq]pool.bin\[rq] pool file, print what would be repaired with increased verbosity level. .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7), \f[B]libpmempool\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-convert.1000066400000000000000000000050421331545616200205520ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-CONVERT" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-convert\f[] \- upgrade pool files layout version .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ convert\ \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool\f[] invoked with the \f[I]convert\f[] command performs a conversion of the specified pool to the newest layout supported by this tool. Currently only \f[B]libpmemobj\f[](7) pools are supported. It is advised to have a backup of the pool before conversion. .RS .PP NOTE: The conversion process is not fail\-safe \- power interruption may damage the pool. .RE .SH EXAMPLE .IP .nf \f[C] $\ pmempool\ convert\ pool.obj \f[] .fi .PP Updates pool.obj to the latest layout version. .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7), \f[B]libpmempool\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-create.1000066400000000000000000000131331331545616200203350ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-CREATE" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-create\f[] \[en] create a persistent memory pool .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ create\ []\ []\ []\ \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool\f[] invoked with \f[I]create\f[] command creates a pool file of specified type. Depending on a pool type it is possible to provide more properties of pool. .PP Valid pool types are: \f[B]blk\f[], \f[B]log\f[] and \f[B]obj\f[] which stands for \f[I]pmemblk\f[], \f[I]pmemlog\f[] and \f[I]pmemobj\f[] pools respectively. By default the pool file is created with \f[I]minimum\f[] allowed size for specified pool type. The minimum sizes for \f[B]blk\f[], \f[B]log\f[] and \f[B]obj\f[] pool types are \f[B]PMEMBLK_MIN_POOL\f[], \f[B]PMEMLOG_MIN_POOL\f[] and \f[B]PMEMOBJ_MIN_POOL\f[] respectively. See \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7) and \f[B]libpmemobj\f[](7) for details. .PP For \f[I]pmemblk\f[] pool type block size \f[I]\f[] is a required argument. .PP In order to set custom size of pool use \f[B]\-s\f[] option, or use \f[B]\-M\f[] option to create a pool of maximum available size on underlying file system. .PP The \f[I]size\f[] argument may be passed in format that permits only the upper\-case character for byte \- B as specified in IEC 80000\-13, IEEE 1541 and the Metric Interchange Format. Standards accept SI units with obligatory B \- kB, MB, GB, \&... which means multiplier by 1000 and IEC units with optional \[lq]iB\[rq] \- KiB, MiB, GiB, \&..., K, M, G, \&... \- which means multiplier by 1024. .SS Available options: .PP \f[C]\-s,\ \-\-size\ \f[] .PP Size of pool file. .PP \f[C]\-M,\ \-\-max\-size\f[] .PP Set size of pool to available space of underlying file system. .PP \f[C]\-m,\ \-\-mode\ \f[] .PP Set permissions to (the default is 0664) when creating the files. If the file already exist the permissions are not changed. .PP \f[C]\-i,\ \-\-inherit\ \f[] .PP Create a new pool of the same size and other properties as \f[I]\f[]. .PP \f[C]\-f,\ \-\-force\f[] .PP Remove the pool before creating. .PP \f[C]\-v,\ \-\-verbose\f[] .PP Increase verbosity level. .PP \f[C]\-h,\ \-\-help\f[] .PP Display help message and exit. .SS Options for PMEMBLK: .PP By default when creating a pmem \f[B]blk\f[] pool, the \f[B]BTT\f[] layout is \f[I]not\f[] written until the first \f[I]write operation\f[] of block entry is performed. Using \f[B]\-w\f[] option you can force writing the \f[B]BTT\f[] layout by writing zero data to specified block number. By default the \f[I]write operation\f[] is performed to block number 0. Please refer to \f[B]libpmemblk\f[](7) for details. .PP \f[C]\-w,\ \-\-write\-layout\f[] .PP Force writing the \f[B]BTT\f[] layout by performing \f[I]write operation\f[] to block number zero. .SS Options for PMEMOBJ: .PP By default when creating a pmem \f[B]obj\f[] pool, the layout name provided to the \f[B]libpmemobj\f[] library is an empty string. Please refer to \f[B]libpmemobj\f[](7) for details. .PP \f[C]\-l,\ \-\-layout\ \f[] .PP Layout name of the \f[B]pmemobj\f[] pool. .SH EXAMPLE .IP .nf \f[C] $\ pmempool\ create\ blk\ 512\ pool.blk \f[] .fi .PP Create a blk pool file of minimum allowed size and block size 512 bytes .IP .nf \f[C] $\ pmempool\ create\ log\ \-M\ pool.log \f[] .fi .PP Create a log pool file of maximum allowed size .IP .nf \f[C] $\ pmempool\ create\ blk\ \-\-size=4G\ \-\-write\-layout\ 1K\ pool.blk \f[] .fi .PP Create a blk pool file of size 4G, block size 1K and write the BTT layout .IP .nf \f[C] $\ pmempool\ create\ \-\-layout\ my_layout\ obj\ pool.obj \f[] .fi .PP Create an obj pool file of minimum allowed size and layout \[lq]my_layout\[rq] .IP .nf \f[C] $\ pmempool\ create\ \-\-inherit=pool.log\ new_pool.log \f[] .fi .PP Create a pool file based on pool.log file .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-dump.1000066400000000000000000000102321331545616200200340ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-DUMP" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-dump\f[] \[en] dump user data from persistent memory pool .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ dump\ []\ \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool\f[] invoked with \f[I]dump\f[] command dumps user data from specified pool file. The output format may be either binary or hexadecimal. .PP By default the output format is hexadecimal. .PP By default data is dumped to standard output. It is possible to dump data to other file by specifying \f[B]\-o\f[] option. In this case data will be appended to this file. .PP Using \f[B]\-r\f[] option you can specify number of blocks/bytes/data chunks using special text format. See \f[B]RANGE\f[] section for details. .SS Available options: .PP \f[C]\-b,\ \-\-binary\f[] .PP Dump data in binary format. .PP \f[C]\-r,\ \-\-range\ \f[] .PP Range of pool file to dump. This may be number of blocks for \f[B]blk\f[] pool type or either number of bytes or number of data chunks for \f[B]log\f[] pool type. .PP \f[C]\-c,\ \-\-chunk\ \f[] .PP Size of chunk for \f[B]log\f[] pool type. See \f[B]pmemlog_walk\f[](3) in \f[B]libpmemlog\f[](7) for details. .PP \f[C]\-o,\ \-\-output\ \f[] .PP Name of output file. .PP \f[C]\-h,\ \-\-help\f[] .PP Display help message and exit. .SH RANGE .PP Using \f[B]\-r\f[], \f[B]\[en]range\f[] option it is possible to dump only a range of user data. This section describes valid format of \f[I]\f[] string. .PP You can specify multiple ranges separated by commas. .PP \f[C]\-\f[] .PP All blocks/bytes/data chunks from \f[I]\f[] to \f[I]\f[] will be dumped. .PP \f[C]\-\f[] .PP All blocks/bytes/data chunks up to \f[I]\f[] will be dumped. .PP \f[C]\-\f[] .PP All blocks/bytes/data chunks starting from \f[I]\f[] will be dumped. .PP \f[C]\f[] .PP Only \f[I]\f[] block/byte/data chunk will be dumped. .SH EXAMPLE .IP .nf \f[C] $\ pmempool\ dump\ pool.bin \f[] .fi .PP Dump user data from pool.bin file to standard output .IP .nf \f[C] $\ pmempool\ dump\ \-o\ output.bin\ \-r1,10\-100\ pool_blk.bin \f[] .fi .PP Dump block number 1 and blocks from 10 to 100 from pool_blk.bin containing pmem blk pool to output.bin file .IP .nf \f[C] $\ pmempool\ dump\ \-r\ 1K\-2K\ pool.bin \f[] .fi .PP Dump data form 1K to 2K from pool.bin file. .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-info.1000066400000000000000000000360001331545616200200230ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-INFO" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-info\f[] \[en] show information about persistent memory pool .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ info\ []\ \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool\f[] invoked with \f[I]info\f[] command analyzes an existing pool created by \f[B]PMDK\f[] libraries provided by \f[B]file\f[] parameter. The \f[B]file\f[] can be either existing pool file, a part file or a poolset file. .PP The main task of this command is to print all usable information from pool headers and user data in human readable format. It automatically recognizes the pool type by parsing and analyzing the pool header. The recognition is done by checking the signature in the pool header. The main job of \f[I]info\f[] command is to present internal data structures as they are stored in file but \f[I]not\f[] for checking consistency. For this purpose there is the \f[B]pmempool\-check\f[](1) command available. .PP The \f[B]pmempool\f[] with \f[I]info\f[] command analyzes pool file as long as it is possible regarding \f[I]correctness\f[] of internal meta\-data (correct offsets, sizes etc.). If it is \f[I]not\f[] possible to analyze the rest of the file, \f[B]pmempool\f[] exits with error code and prints appropriate error message. .PP Currently there is lack of interprocess synchronization for pool files, so the \f[I]info\f[] command should be invoked off\-line. Using \f[B]pmempool\f[] on pool file which may be modified by another process may lead to unexpected errors in pool file. .PP A poolset file passed to \f[B]pmempool info\f[] may contain multiple replicas, also remote ones, but \f[B]pmempool\f[] currently does not read any data from remote replicas. It prints only a remote node address and a remote replica descriptor. .PP \f[B]pmempool info\f[] opens pool file in \f[I]read\-only\f[] mode so the file will remain untouched after processing. .PP The \f[I]info\f[] command may collect and print basic statistics about data usage. The statistics are specific to the type of pool. See \f[B]STATISTICS\f[] section for details. .PP Although the pool consistency is \f[I]not\f[] checked by the \f[I]info\f[] command, it prints information about checksum errors and/or offsets errors. .SS Common options: .PP By default the \f[I]info\f[] command of \f[B]pmempool\f[] prints information about the most important internal data structures from pool. The particular set of headers and meta\-data depend on pool type. The pool type is recognized automatically and appropriate information is displayed in human\-readable format. .PP To force processing specified file(s) as desired pool type use \f[B]\-f\f[] option with appropriate name of pool type. The valid names off pool types are \f[B]blk\f[], \f[B]log\f[], \f[B]obj\f[] or \f[B]btt\f[]. This option may be useful when the pool header is corrupted and automatic recognition of pool type fails. .PP \f[C]\-f,\ \-\-force\ blk|log|obj|btt\f[] .PP Force parsing pool as specified pool type. .RS .PP NOTE: By default only pool headers and internal meta\-data are displayed. To display user data use \f[B]\-d\f[] option. Using \f[B]\-r\f[] option you can specify number of blocks/bytes/data chunks or objects using special text format. See \f[B]RANGE\f[] section for details. The range refers to \f[I]block numbers\f[] in case of pmem blk pool type, to \f[I]chunk numbers\f[] in case of pmem log pool type and to \f[I]object numbers\f[] in case of pmem obj pool type. See \f[B]EXAMPLES\f[] section for an example of usage of these options. .RE .PP \f[C]\-d,\ \-\-data\f[] .PP Dump user data in hexadecimal format. In case of pmem \f[I]blk\f[] pool type data is dumped in \f[I]blocks\f[]. In case of pmem \f[I]log\f[] pool type data is dumped as a wholeor in \f[I]chunks\f[] if \f[B]\-w\f[] option is used (See \f[B]Options for PMEMLOG\f[] section for details). .PP \f[C]\-r,\ \-\-range\ \f[] .PP Range of blocks/data chunks/objects/zone headers/chunk headers/lanes. See \f[B]RANGE\f[] section for details about range format. .PP \f[C]\-n,\ \-\-human\f[] .PP Print sizes in human\-readable format with appropriate units (e.g.\ 4k, 8M, 16G) .PP \f[C]\-x,\ \-\-headers\-hex\f[] .PP Print pool's internal data in mixed format which consists of hexadecimal dump of header's data and parsed format displayed in human\-readable format. This allows to see how data is stored in file. .PP \f[C]\-s,\ \-\-stats\f[] .PP Print pool's statistics. See \f[B]STATISTICS\f[] section for details. .PP \f[C]\-h,\ \-\-help\f[] .PP Display help message and exit. .SS Options for PMEMLOG: .PP \f[C]\-w,\ \-\-walk\ \f[] .PP Use this option to walk through used data with fixed data chunk size. See \f[B]pmemlog_walk\f[](3) in \f[B]libpmemlog\f[](7) for details. .SS Options for PMEMBLK: .PP By default the \f[I]info\f[] command displays the \f[B]pmemblk\f[] header and BTT (Block Translation Table) Info header in case of \f[B]pmemblk\f[] pool type. .PP To display BTT Map and/or BTT FLOG (Free List and Log) use \f[B]\-m\f[] and \f[B]\-g\f[] options respectively or increase verbosity level. .PP In order to display BTT Info header backup use \f[B]\-B\f[] option. .PP \f[C]\-m,\ \-\-map\f[] .PP Print BTT Map entries. .PP \f[C]\-g,\ \-\-flog\f[] .PP Print BTT FLOG entries. .PP \f[C]\-B,\ \-\-backup\f[] .PP Print BTT Info header backup. .RS .PP NOTE: By default the \f[I]info\f[] command displays all data blocks when \f[B]\-d\f[] options is used. However it is possible to skip blocks marked with \f[I]zero\f[] and/or \f[I]error\f[] flags. It is also possible to skip blocks which are \f[I]not\f[] marked with any flag. Skipping blocks has impact on blocks ranges (e.g.\ display 10 blocks marked with error flag in the range from 0 to 10000) and statistics. .RE .PP \f[C]\-z,\ \-\-skip\-zeros\f[] .PP Skip blocks marked with \f[I]zero\f[] flag. .PP \f[C]\-e,\ \-\-skip\-error\f[] .PP Skip blocks marked with \f[I]error\f[] flag. .PP \f[C]\-u,\ \-\-skip\-no\-flag\f[] .PP Skip blocks \f[I]not\f[] marked with any flag. .SS Options for PMEMOBJ: .PP By default the \f[I]info\f[] command displays pool header and \f[B]pmemobj\f[] pool descriptor. In order to print information about other data structures one of the following options may be used. .PP \f[C]\-l,\ \-\-lanes\ []\f[] .PP Print information about lanes. If range is not specified all lanes are displayed. The range can be specified using \f[B]\-r\f[] option right after the \f[B]\-l\f[] option. See \f[B]RANGE\f[] section for details about range format. .PP \f[C]\-R,\ \-\-recovery\f[] .PP Print information about only those lanes which require recovery process. This option requires \f[B]\-l\f[], \f[B]\[en]lanes\f[] option. .PP \f[C]\-S,\ \-\-section\ tx,allocator,list\f[] .PP Print information only about specified sections from lane. The section types may be separated by comma. This option requires \f[B]\-l\f[], \f[B]\[en]lanes\f[] option. .PP \f[C]\-O,\ \-\-object\-store\f[] .PP Print information about all allocated objects. .PP \f[C]\-t,\ \-\-types\ \f[] .PP Print information about allocated objects only from specified range of type numbers. If \f[B]\-s\f[], \f[B]\[en]stats\f[] option is specified the objects statistics refer to objects from specified range of type numbers. This option requires \f[B]\-O\f[], \f[B]\[en]object\-store\f[] or \f[B]\-s\f[], \f[B]\[en]stats\f[] options. See \f[B]RANGE\f[] section for details about range format. .PP \f[C]\-E,\ \-\-no\-empty\f[] .PP Ignore empty lists of objects. This option requires \f[B]\-O\f[], \f[B]\[en]object\-store\f[] option. .PP \f[C]\-o,\ \-\-root\f[] .PP Print information about a root object. .PP \f[C]\-A,\ \-\-alloc\-header\f[] .PP Print object's allocation header. This option requires \f[B]\-O\f[], \f[B]\[en]object\-store\f[] or \f[B]\-l\f[], \f[B]\[en]lanes\f[] or \f[B]\-o\f[], \f[B]\[en]root\f[] options. .PP \f[C]\-a,\ \-\-oob\-header\f[] .PP Print object's out of band header. This option requires \f[B]\-O\f[], \f[B]\[en]object\-store\f[] or \f[B]\-l\f[], \f[B]\[en]lanes\f[] or \f[B]\-o\f[], \f[B]\[en]root\f[] options. .PP \f[C]\-H,\ \-\-heap\f[] .PP Print information about \f[B]pmemobj\f[] heap. By default only a heap header is displayed. .PP \f[C]\-Z,\ \-\-zones\f[] .PP If the \f[B]\-H\f[], \f[B]\[en]heap\f[] option is used, print information about zones from specified range. If the \f[B]\-O\f[], \f[B]\[en]object\-store\f[] option is used, print information about objects only from specified range of zones. This option requires \f[B]\-O\f[], \f[B]\[en]object\-store\f[], \f[B]\-H\f[], \f[B]\[en]heap\f[] or \f[B]\-s\f[], \f[B]\[en]stats\f[] options. The range can be specified using \f[B]\-r\f[] option right after the \f[B]\-Z\f[] option. See \f[B]RANGE\f[] section for details about range format. .PP \f[C]\-C,\ \-\-chunks\ []\f[] .PP If the \f[B]\-H, \[en]heap\f[] option is used, print information about chunks from specified range. By default information about chunks of types \f[I]used\f[] , \f[I]free\f[] and \f[I]run\f[] are displayed. If the \f[B]\-O, \[en]object\-store\f[] option is used, print information about objects from specified range of chunks within a zone. This option requires \f[B]\-O, \[en]object\-store\f[], \f[B]\-H, \[en]heap\f[] or \f[B]\-s, \[en]stats\f[] options. The range can be specified using \f[B]\-r\f[] option right after the \f[B]\-C\f[] option. See \f[B]RANGE\f[] section for details about range format. .PP \f[C]\-T,\ \-\-chunk\-type\ used,free,run,footer\f[] .PP Print only specified type(s) of chunks. The multiple types may be specified separated by comma. This option requires \f[B]\-H, \[en]heap\f[] and \f[B]\-C, \[en]chunks\f[] options. .PP \f[C]\-b,\ \-\-bitmap\f[] .PP Print bitmap of used blocks in chunks of type run. This option requires \f[B]\-H, \[en]heap\f[] and \f[B]\-C, \[en]chunks\f[] options. .PP \f[C]\-p,\ \-\-replica\ \f[] .PP Print information from \f[I]\f[] replica. The 0 value means the master pool file. .SH RANGE .PP Using \f[B]\-r, \[en]range\f[] option it is possible to dump only a range of user data. This section describes valid format of \f[I]\f[] string. .PP You can specify multiple ranges separated by commas. .PP \f[C]\-\f[] .PP All blocks/bytes/data chunks from \f[I]\f[] to \f[I]\f[] will be dumped. .PP \f[C]\-\f[] .PP All blocks/bytes/data chunks up to \f[I]\f[] will be dumped. .PP \f[C]\-\f[] .PP All blocks/bytes/data chunks starting from \f[I]\f[] will be dumped. .PP \f[C]\f[] .PP Only \f[I]\f[] block/byte/data chunk will be dumped. .SH STATISTICS .PP Below is the description of statistical measures for specific pool types. .SS PMEMLOG .IP \[bu] 2 \f[B]Total\f[] \- Total space in pool. .IP \[bu] 2 \f[B]Available\f[] \- Size and percentage of available space. .IP \[bu] 2 \f[B]Used\f[] \- Size and percentage of used space. .SS PMEMBLK .IP \[bu] 2 \f[B]Total blocks\f[] \- Total number of blocks in pool. .IP \[bu] 2 \f[B]Zeroed blocks\f[] \- Number and percentage of blocks marked with \f[I]zero\f[] flag. .IP \[bu] 2 \f[B]Error blocks\f[] \- Number and percentage of blocks marked with \f[I]error\f[] flag. .IP \[bu] 2 \f[B]Blocks without any flag\f[] \- Number and percentage of blocks \f[I]not\f[] marked with any flag. .RS .PP NOTE: In case of pmemblk, statistics are evaluated for blocks which meet requirements regarding: \f[I]range\f[] of blocks (\f[B]\-r\f[] option), \f[I]skipped\f[] types of blocks (\f[B]\-z\f[], \f[B]\-e\f[], \f[B]\-u\f[] options). .RE .SS PMEMOBJ .IP \[bu] 2 \f[B]Object store\f[] .RS 2 .IP \[bu] 2 \f[B]Number of objects\f[] \- Total number of objects and number of objects per type number. .IP \[bu] 2 \f[B]Number of bytes\f[] \- Total number of bytes and number of bytes per type number. .RE .IP \[bu] 2 \f[B]Heap\f[] .RS 2 .IP \[bu] 2 \f[B]Number of zones\f[] \- Total number of zones in the pool. .IP \[bu] 2 \f[B]Number of used zones\f[] \- Number of used zones in the pool. .RE .IP \[bu] 2 \f[B]Zone\f[] The zone's statistics are presented for each zone separately and the aggregated results from all zones. .RS 2 .IP \[bu] 2 \f[B]Number of chunks\f[] \- Total number of chunks in the zone and number of chunks of specified type. .IP \[bu] 2 \f[B]Chunks size\f[] \- Total size of all chunks in the zone and sum of sizes of chunks of specified type. .RE .IP \[bu] 2 \f[B]Allocation classes\f[] .RS 2 .IP \[bu] 2 \f[B]Units\f[] \- Total number of units of specified class. .IP \[bu] 2 \f[B]Used units\f[] \- Number of used units of specified class. .IP \[bu] 2 \f[B]Bytes\f[] \- Total number of bytes of specified class. .IP \[bu] 2 \f[B]Used bytes\f[] \- Number of used bytes of specified class. .IP \[bu] 2 \f[B]Total bytes\f[] \- Total number of bytes of all classes. .IP \[bu] 2 \f[B]Total used bytes\f[] \- Total number of used bytes of all classes. .RE .SH EXAMPLE .IP .nf \f[C] $\ pmempool\ info\ ./pmemblk \f[] .fi .PP Parse and print information about \[lq]pmemblk\[rq] pool file. .IP .nf \f[C] $\ pmempool\ info\ \-f\ blk\ ./pmempool \f[] .fi .PP Force parsing \[lq]pmempool\[rq] file as \f[B]pmemblk\f[] pool type. .IP .nf \f[C] $\ pmempool\ info\ \-d\ ./pmemlog \f[] .fi .PP Print information and data in hexadecimal dump format for file \[lq]pmemlog\[rq]. .IP .nf \f[C] $\ pmempool\ info\ \-d\ \-r10\-100\ \-eu\ ./pmemblk \f[] .fi .PP Print information from \[lq]pmemblk\[rq] file. Dump data blocks from 10 to 100, skip blocks marked with error flag and not marked with any flag. .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-rm.1000066400000000000000000000103421331545616200175070ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-RM" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-rm\f[] \[en] remove a persistent memory pool .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ rm\ []\ .. \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool rm\f[] command removes each specified file. If the specified file is a pool set file, all pool files (single\-file pool or part files) and remote replicas are removed. By default the \f[B]pmempool rm\f[] does not remove pool set files. All local and remote pool files are removed using \f[B]unlink\f[](3) call, except the pools created on \f[B]device dax\f[] which are zeroed instead. If specified file does not exist, the remote pool is broken or not accessible, the \f[B]pmempool rm\f[] command terminates with an error code. By default it prompts before removing \f[I]write\-protected\f[] local files. See \f[B]REMOTE REPLICATION\f[] section for more details about support for remote pools. See \f[B]EXAMPLES\f[] section for example usage of the \f[I]rm\f[] command. .SS Available options: .PP \f[C]\-h,\ \-\-help\f[] .PP Print help message .PP \f[C]\-v,\ \-\-verbose\f[] .PP Be verbose and print all removing files. .PP \f[C]\-s,\ \-\-only\-pools\f[] .PP Remove only pool files and do not remove pool set files (default behaviour). .PP \f[C]\-a,\ \-\-all\f[] .PP Remove all pool set files \- local and remote. .PP \f[C]\-l,\ \-\-local\f[] .PP Remove local pool set files. .PP \f[C]\-r,\ \-\-remote\f[] .PP Remove remote pool set files. .PP \f[C]\-f,\ \-\-force\f[] .PP Remove all specified files, ignore nonexistent files, never prompt. .PP \f[C]\-i,\ \-\-interactive\f[] .PP Prompt before removing every single file or remote pool. .SH REMOTE REPLICATION .PP A remote pool is removed using \f[B]rpmem_remove\f[](3) function if \f[B]librpmem\f[](7) library is available. If a pool set file contains remote replication but \f[B]librpmem\f[](7) is not available, the \f[B]pmempool rm\f[] command terminates with an error code, unless the \f[B]\-f, \[en]force\f[] option is specified. .SH EXAMPLE .IP .nf \f[C] $\ pmempool\ rm\ pool.obj\ pool.blk \f[] .fi .PP Remove specified pool files. .IP .nf \f[C] $\ pmempool\ rm\ pool.set \f[] .fi .PP Remove all pool files from the \[lq]pool.set\[rq], do not remove \f[I]pool.set\f[] itself. .IP .nf \f[C] $\ pmempool\ rm\ \-a\ pool.set \f[] .fi .PP Remove all pool files from the \[lq]pool.set\[rq], remove the local pool set file and all remote pool set files. .SH SEE ALSO .PP \f[B]pmempool\f[](1), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7), \f[B]librpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-sync.1000066400000000000000000000064101331545616200200460ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-SYNC" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-sync\f[] \[en] Synchronize replicas or their parts within a pool set. .SH SYNOPSIS .IP .nf \f[C] pmempool\ sync\ [options]\ \f[] .fi .PP NOTE: Only the pool set file used to create the pool should be used for syncing the pool. .SH DESCRIPTION .PP The \f[B]pmempool sync\f[] command synchronizes data between replicas within a pool set. It checks if metadata of all replicas in a pool set are consistent, i.e.\ all parts are healthy, and if any of them is not, the corrupted or missing parts are recreated and filled with data from one of the healthy replicas. Currently synchronizing data is allowed only for \f[B]pmemobj\f[] pools (see \f[B]libpmemobj\f[](7)). .PP If a pool set has the option \f[I]SINGLEHDR\f[] or \f[I]NOHDRS\f[] (see \f[B]poolset\f[](5)), \f[B]pmempool sync\f[] command has limited capability of checking its metadata. This is due to limited or no, respectively, internal metadata at the beginning of pool set parts in every replica when either of the options is used. In that cases, only missing parts or the ones which cannot be opened are recreated. .SS Available options: .TP .B \f[C]\-d,\ \-\-dry\-run\f[] Enable dry run mode. In this mode no changes are applied, only check for viability of synchronization. .RS .RE .TP .B \f[C]\-v,\ \-\-verbose\f[] Increase verbosity level. .RS .RE .TP .B \f[C]\-h,\ \-\-help\f[] Display help message and exit. .RS .RE .SH SEE ALSO .PP \f[B]pmempool(1)\f[], \f[B]libpmemblk(7)\f[], \f[B]libpmemlog(7)\f[], \f[B]libpmempool(7)\f[] and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool-transform.1000066400000000000000000000135251331545616200211120ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL-TRANSFORM" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\-transform\f[] \[en] Modify internal structure of a pool set. .SH SYNOPSIS .IP .nf \f[C] pmempool\ transform\ [options]\ \ \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool transform\f[] command modifies internal structure of a pool set defined by the \f[C]poolset_file_src\f[] file, according to a structure described in the \f[C]poolset_file_dst\f[] file. .PP The following operations are supported: .IP \[bu] 2 adding replicas \- one or more new replicas can be added and synchronized with other replicas in the pool set, .IP \[bu] 2 removing replicas \- one or more replicas can be removed from the pool set , .IP \[bu] 2 adding or removing pool set options. .PP Only one of the above operations can be performed at a time. .PP Currently adding and removing replicas are allowed only for \f[B]pmemobj\f[] pools (see \f[B]libpmemobj\f[](7)). .PP The \f[I]poolset_file_src\f[] argument provides the source pool set to be changed. .PP The \f[I]poolset_file_dst\f[] argument points to the target pool set. .PP When adding or deleting replicas, the two pool set files can differ only in the definitions of replicas which are to be added or deleted. When adding or removing pool set options (see \f[B]poolset\f[](5)), the rest of both pool set files have to be of the same structure. The operation of adding/removing a pool set option can be performed on a pool set with local replicas only. To add/remove a pool set option to/from a pool set with remote replicas, one has to remove the remote replicas first, then add/remove the option, and finally recreate the remote replicas having added/removed the pool set option to/from the remote replicas' poolset files. To add a replica it is necessary for its effective size to match or exceed the pool size. Otherwise the whole operation fails and no changes are applied. If none of the poolset options is used, the effective size of a replica is the sum of sizes of all its part files decreased by 4096 bytes per each part file. The 4096 bytes of each part file is utilized for storing internal metadata of the pool part files. If the option \f[I]SINGLEHDR\f[] is used, the effective size of a replica is the sum of sizes of all its part files decreased once by 4096 bytes. In this case only the first part contains internal metadata. If the option \f[I]NOHDRS\f[] is used, the effective size of a replica is the sum of sizes of all its part files. In this case none of the parts contains internal metadata. .SS Available options: .TP .B \f[C]\-d,\ \-\-dry\-run\f[] Enable dry run mode. In this mode no changes are applied, only check for viability of the operation is performed. .RS .RE .TP .B \f[C]\-v,\ \-\-verbose\f[] Increase verbosity level. .RS .RE .TP .B \f[C]\-h,\ \-\-help\f[] Display help message and exit. .RS .RE .SH EXAMPLES .SS Example 1. .PP Let files \f[C]/path/poolset_file_src\f[] and \f[C]/path/poolset_file_dst\f[] have the following contents: .IP .nf \f[C] PMEMPOOLSET 20M\ /0/partfile1 20M\ /0/partfile2 25M\ /0/partfile3 REPLICA 40M\ /1/partfile1 20M\ /1/partfile2 \f[] .fi .IP .nf \f[C] PMEMPOOLSET 20M\ /0/partfile1 20M\ /0/partfile2 25M\ /0/partfile3 REPLICA 40M\ /1/partfile1 20M\ /1/partfile2 REPLICA 50M\ /2/partfile1 20M\ /2/partfile2 \f[] .fi .PP Then, the command .PP \f[C]pmempool\ transform\ /path/poolset_file_src\ /path/poolset_file_dst\f[] .PP adds a replica to the pool set. All other replicas remain unchanged and the size of the pool remains 60M. .SS Example 2. .PP Let files \f[C]/path/poolset_file_src\f[] and \f[C]/path/poolset_file_dst\f[] have the following contents: .IP .nf \f[C] PMEMPOOLSET 20M\ /0/partfile1 20M\ /0/partfile2 25M\ /0/partfile3 REPLICA 40M\ /1/partfile1 20M\ /1/partfile2 \f[] .fi .IP .nf \f[C] PMEMPOOLSET 20M\ /0/partfile1 20M\ /0/partfile2 25M\ /0/partfile3 \f[] .fi .PP Then .PP \f[C]pmempool_transform\ /path/poolset_file_src\ /path/poolset_file_dst\f[] .PP deletes the second replica from the pool set. The first replica remains unchanged and the size of the pool is still 60M. .SH SEE ALSO .PP \f[B]pmempool(1)\f[], \f[B]libpmemblk(7)\f[], \f[B]libpmemlog(7)\f[], \f[B]libpmempool(7)\f[] and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool.1000066400000000000000000000077151331545616200171050ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL" "1" "2018-05-21" "PMDK - pmem Tools version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool\f[] \[en] Persistent Memory Pool Management Tool .SH SYNOPSIS .IP .nf \f[C] $\ pmempool\ [\-\-help]\ [\-\-version]\ \ [] \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool\f[] is a management tool for \f[I]Persistent Memory\f[] pool files created by \f[B]PMDK\f[] libraries. .PP The main purpose of \f[B]pmempool\f[] is to provide a user with a set of utilities for off\-line analysis and manipulation of pools created by pmem libraries. The pmempool is a generic command which consists of subcommands for specific purposes. Some of subcommands are required to work \f[I]without\f[] any impact on processed pool, but some of them \f[I]may\f[] create a new or modify an existing one. .PP The \f[B]pmempool\f[] may be useful for troubleshooting by system administrators and for software developers who work on applications based on \f[B]PMDK\f[]. The latter may find these tools useful for testing and debugging purposes also. .SH OPTIONS .PP \f[C]\-V,\ \-\-version\f[] .PP Prints the version of \f[B]pmempool\f[]. .PP \f[C]\-h,\ \-\-help\f[] .PP Prints synopsis and list of commands. .SH COMMANDS .PP Currently there is a following set of commands available: .IP \[bu] 2 \f[B]pmempool\-info\f[](1) \- Prints information and statistics in human\-readable format about specified pool. .IP \[bu] 2 \f[B]pmempool\-check\f[](1) \- Checks pool's consistency and repairs pool if it is not consistent. .IP \[bu] 2 \f[B]pmempool\-create\f[](1) \- Creates a pool of specified type with additional properties specific for this type of pool. .IP \[bu] 2 \f[B]pmempool\-dump\f[](1) \- Dumps usable data from pool in hexadecimal or binary format. .IP \[bu] 2 \f[B]pmempool\-rm\f[](1) Removes pool file or all pool files listed in pool set configuration file. .IP \[bu] 2 \f[B]pmempool\-convert\f[](1) \- Updates the pool to the latest available layout version. .IP \[bu] 2 \f[B]pmempool\-sync\f[](1) \- Synchronizes replicas within a poolset. .IP \[bu] 2 \f[B]pmempool\-transform\f[](1) \- Modifies internal structure of a poolset. .PP In order to get more information about specific \f[I]command\f[] you can use \f[B]pmempool help .\f[] .SH SEE ALSO .PP \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool_check.3000066400000000000000000000000321331545616200202250ustar00rootroot00000000000000.so pmempool_check_init.3 pmdk-1.4.1/doc/generated/pmempool_check_end.3000066400000000000000000000000321331545616200210530ustar00rootroot00000000000000.so pmempool_check_init.3 pmdk-1.4.1/doc/generated/pmempool_check_init.3000066400000000000000000000223011331545616200212530ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL_CHECK_INIT" "3" "2018-05-21" "PMDK - pmempool API version 1.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool_check_init\f[](), \f[B]pmempool_check\f[](), \f[B]pmempool_check_end\f[]() \[en] checks pmempool health .SH SYNOPSIS .IP .nf \f[C] #include\ PMEMpoolcheck\ *pmempool_check_init(struct\ pmempool_check_args\ *args,\ \ \ \ \ size_t\ args_size); struct\ pmempool_check_status\ *pmempool_check(PMEMpoolcheck\ *ppc); enum\ pmempool_check_result\ pmempool_check_end(PMEMpoolcheck\ *ppc); \f[] .fi .SH DESCRIPTION .PP To perform the checks provided by \f[B]libpmempool\f[], a \f[I]check context\f[] must first be initialized using the \f[B]pmempool_check_init\f[]() function described in this section. Once initialized, the \f[I]check context\f[] is represented by an opaque handle of type \f[I]PMEMpoolcheck*\f[], which is passed to all of the other functions available in \f[B]libpmempool\f[] .PP To execute checks, \f[B]pmempool_check\f[]() must be called iteratively. Each call generates a new check status, represented by a \f[I]struct pmempool_check_status\f[] structure. Status messages are described later below. .PP When the checks are completed, \f[B]pmempool_check\f[]() returns NULL. The check must be finalized using \f[B]pmempool_check_end\f[](), which returns an \f[I]enum pmempool_check_result\f[] describing the results of the entire check. .PP \f[B]pmempool_check_init\f[]() initializes the check context. \f[I]args\f[] describes parameters of the check context. \f[I]args_size\f[] should be equal to the size of the \f[I]struct pmempool_check_args\f[]. \f[I]struct pmempool_check_args\f[] is defined as follows: .IP .nf \f[C] struct\ pmempool_check_args { \ \ \ \ /*\ path\ to\ the\ pool\ to\ check\ */ \ \ \ \ const\ char\ *path; \ \ \ \ /*\ optional\ backup\ path\ */ \ \ \ \ const\ char\ *backup_path; \ \ \ \ /*\ type\ of\ the\ pool\ */ \ \ \ \ enum\ pmempool_pool_type\ pool_type; \ \ \ \ /*\ parameters\ */ \ \ \ \ int\ flags; }; \f[] .fi .PP The \f[I]flags\f[] argument accepts any combination of the following values (ORed): .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_REPAIR\f[] \- perform repairs .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_DRY_RUN\f[] \- emulate repairs, not supported on Device DAX .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_ADVANCED\f[] \- perform hazardous repairs .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_ALWAYS_YES\f[] \- do not ask before repairs .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_VERBOSE\f[] \- generate info statuses .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_FORMAT_STR\f[] \- generate string format statuses .PP \f[I]pool_type\f[] must match the type of the \f[I]pool\f[] being processed. Pool type detection may be enabled by setting \f[I]pool_type\f[] to \f[B]PMEMPOOL_POOL_TYPE_DETECT\f[]. A pool type detection failure ends the check. .PP \f[I]backup_path\f[] may be: .IP \[bu] 2 NULL. No backup will be performed. .IP \[bu] 2 a non\-existent file: \f[I]backup_path\f[] will be created and backup will be performed. \f[I]path\f[] must be a single file \f[I]pool\f[]. .IP \[bu] 2 an existing \f[I]pool set\f[] file: Backup will be performed as defined by the \f[I]backup_path\f[] pool set. \f[I]path\f[] must be a pool set, and \f[I]backup_path\f[] must have the same structure (the same number of parts with exactly the same size) as the \f[I]path\f[] pool set. .PP Backup is supported only if the source \f[I]pool set\f[] has no defined replicas. .PP Neither \f[I]path\f[] nor \f[I]backup_path\f[] may specify a pool set with remote replicas. .PP The \f[B]pmempool_check\f[]() function starts or resumes the check indicated by \f[I]ppc\f[]. When the next status is generated, the check is paused and \f[B]pmempool_check\f[]() returns a pointer to the \f[I]struct pmempool_check_status\f[] structure: .IP .nf \f[C] struct\ pmempool_check_status { \ \ \ \ enum\ pmempool_check_msg_type\ type;\ /*\ type\ of\ the\ status\ */ \ \ \ \ struct \ \ \ \ { \ \ \ \ \ \ \ \ const\ char\ *msg;\ /*\ status\ message\ string\ */ \ \ \ \ \ \ \ \ const\ char\ *answer;\ /*\ answer\ to\ message\ if\ applicable\ */ \ \ \ \ }\ str; }; \f[] .fi .PP This structure can describe three types of statuses: .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_MSG_TYPE_INFO\f[] \- detailed information about the check. Generated only if a \f[B]PMEMPOOL_CHECK_VERBOSE\f[] flag was set. .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_MSG_TYPE_ERROR\f[] \- An error was encountered. .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_MSG_TYPE_QUESTION\f[] \- question. Generated only if an \f[B]PMEMPOOL_CHECK_ALWAYS_YES\f[] flag was not set. It requires \f[I]answer\f[] to be set to \[lq]yes\[rq] or \[lq]no\[rq] before continuing. .PP After calling \f[B]pmempool_check\f[]() again, the previously provided \f[I]struct pmempool_check_status\f[] pointer must be considered invalid. .PP The \f[B]pmempool_check_end\f[]() function finalizes the check and releases all related resources. \f[I]ppc\f[] is invalid after calling \f[B]pmempool_check_end\f[](). .SH RETURN VALUE .PP \f[B]pmempool_check_init\f[]() returns an opaque handle of type \f[I]PMEMpoolcheck*\f[]. If the provided parameters are invalid or the initialization process fails, \f[B]pmempool_check_init\f[]() returns NULL and sets \f[I]errno\f[] appropriately. .PP Each call to \f[B]pmempool_check\f[]() returns a pointer to a \f[I]struct pmempool_check_status\f[] structure when a status is generated. When the check completes, \f[B]pmempool_check\f[]() returns NULL. .PP The \f[B]pmempool_check_end\f[]() function returns an \f[I]enum pmempool_check_result\f[] summarizing the results of the finalized check. \f[B]pmempool_check_end\f[]() can return one of the following values: .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_RESULT_CONSISTENT\f[] \- the \f[I]pool\f[] is consistent .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_RESULT_NOT_CONSISTENT\f[] \- the \f[I]pool\f[] is not consistent .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_RESULT_REPAIRED\f[] \- the \f[I]pool\f[] has issues but all repair steps completed successfully .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_RESULT_CANNOT_REPAIR\f[] \- the \f[I]pool\f[] has issues which can not be repaired .IP \[bu] 2 \f[B]PMEMPOOL_CHECK_RESULT_ERROR\f[] \- the \f[I]pool\f[] has errors or the check encountered an issue .SH EXAMPLE .PP This is an example of a \f[I]check context\f[] initialization: .IP .nf \f[C] struct\ pmempool_check_args\ args\ = { \ \ \ \ .path\ =\ "/path/to/blk.pool", \ \ \ \ .backup_path\ =\ NULL, \ \ \ \ .pool_type\ =\ PMEMPOOL_POOL_TYPE_BLK, \ \ \ \ .flags\ =\ PMEMPOOL_CHECK_REPAIR\ |\ PMEMPOOL_CHECK_DRY_RUN\ | \ \ \ \ \ \ \ \ PMEMPOOL_CHECK_VERBOSE\ |\ PMEMPOOL_CHECK_FORMAT_STR }; \f[] .fi .IP .nf \f[C] PMEMpoolcheck\ *ppc\ =\ pmempool_check_init(&args,\ sizeof(args)); \f[] .fi .PP The check will process a \f[I]pool\f[] of type \f[B]PMEMPOOL_POOL_TYPE_BLK\f[] located in the path \f[I]/path/to/blk.pool\f[]. Before the check it will not create a backup of the \f[I]pool\f[] (\f[I]backup_path == NULL\f[]). If the check finds any issues it will try to perform repair steps (\f[B]PMEMPOOL_CHECK_REPAIR\f[]), but it will not make any changes to the \f[I]pool\f[] (\f[B]PMEMPOOL_CHECK_DRY_RUN\f[]) and it will not perform any dangerous repair steps (no \f[B]PMEMPOOL_CHECK_ADVANCED\f[]). The check will ask before performing any repair steps (no \f[B]PMEMPOOL_CHECK_ALWAYS_YES\f[]). It will also generate detailed information about the check (\f[B]PMEMPOOL_CHECK_VERBOSE\f[]). The \f[B]PMEMPOOL_CHECK_FORMAT_STR\f[] flag indicates string format statuses (\f[I]struct pmempool_check_status\f[]). Currently this is the only supported status format so this flag is required. .SH NOTES .PP Currently, checking the consistency of a \f[I]pmemobj\f[] pool is \f[B]not\f[] supported. .SH SEE ALSO .PP \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool_check_version.3000066400000000000000000000000271331545616200217760ustar00rootroot00000000000000.so man7/libpmempool.7 pmdk-1.4.1/doc/generated/pmempool_errormsg.3000066400000000000000000000000271331545616200210140ustar00rootroot00000000000000.so man7/libpmempool.7 pmdk-1.4.1/doc/generated/pmempool_rm.3000066400000000000000000000060631331545616200176000ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL_RM" "3" "2018-05-21" "PMDK - pmempool API version 1.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool_rm\f[]() \[en] remove persistent memory pool .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmempool_rm(const\ char\ *path,\ int\ flags); \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool_rm\f[]() function removes the pool pointed to by \f[I]path\f[]. The \f[I]path\f[] can point to a regular file, device dax or pool set file. If \f[I]path\f[] is a pool set file, \f[B]pmempool_rm\f[]() will remove all part files from local replicas using \f[B]unlink\f[](2), and all remote replicas using \f[B]rpmem_remove\f[](3) (see \f[B]librpmem\f[](7)), before removing the pool set file itself. .PP The \f[I]flags\f[] argument determines the behavior of \f[B]pmempool_rm\f[](). It is either 0 or the bitwise OR of one or more of the following flags: .IP \[bu] 2 \f[B]PMEMPOOL_RM_FORCE\f[] \- Ignore all errors when removing part files from local or remote replicas. .IP \[bu] 2 \f[B]PMEMPOOL_RM_POOLSET_LOCAL\f[] \- Also remove local pool set file. .IP \[bu] 2 \f[B]PMEMPOOL_RM_POOLSET_REMOTE\f[] \- Also remove remote pool set file. .SH RETURN VALUE .PP On success, \f[B]pmempool_rm\f[]() returns 0. On error, it returns \-1 and sets \f[I]errno\f[] accordingly. .SH SEE ALSO .PP \f[B]rpmem_remove\f[](3), \f[B]unlink\f[](3), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7), \f[B]librpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool_sync.3000066400000000000000000000141211331545616200201300ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "PMEMPOOL_SYNC" "3" "2018-05-21" "PMDK - pmempool API version 1.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]pmempool_sync\f[](), \f[B]pmempool_transform\f[]() \[en] pool set synchronization and transformation .SH SYNOPSIS .IP .nf \f[C] #include\ int\ pmempool_sync(const\ char\ *poolset_file,\ \ \ \ \ unsigned\ flags);\ (EXPERIMENTAL) int\ pmempool_transform(const\ char\ *poolset_file_src, \ \ \ \ const\ char\ *poolset_file_dst,\ unsigned\ flags);\ (EXPERIMENTAL) \f[] .fi .SH DESCRIPTION .PP The \f[B]pmempool_sync\f[]() function synchronizes data between replicas within a pool set. .PP \f[B]pmempool_sync\f[]() accepts two arguments: .IP \[bu] 2 \f[I]poolset_file\f[] \- a path to a pool set file, .IP \[bu] 2 \f[I]flags\f[] \- a combination of flags (ORed) which modify how synchronization is performed. .RS .PP NOTE: Only the pool set file used to create the pool should be used for syncing the pool. .RE .PP The following flags are available: .IP \[bu] 2 \f[B]PMEMPOOL_DRY_RUN\f[] \- do not apply changes, only check for viability of synchronization. .PP \f[B]pmempool_sync\f[]() checks that the metadata of all replicas in a pool set is consistent, i.e.\ all parts are healthy, and if any of them is not, the corrupted or missing parts are recreated and filled with data from one of the healthy replicas. .PP If a pool set has the option \f[I]SINGLEHDR\f[] (see \f[B]poolset\f[](5)), the internal metadata of each replica is limited to the beginning of the first part in the replica. If the option \f[I]NOHDRS\f[] is used, replicas contain no internal metadata. In both cases, only the missing parts or the ones which cannot be opened are recreated with the \f[B]pmempool_sync\f[]() function. .PP \f[B]pmempool_transform\f[]() modifies the internal structure of a pool set. It supports the following operations: .IP \[bu] 2 adding one or more replicas, .IP \[bu] 2 removing one or more replicas_WINUX(.,, .IP \[bu] 2 adding or removing pool set options.) .PP Only one of the above operations can be performed at a time. .PP \f[B]pmempool_transform\f[]() accepts three arguments: .IP \[bu] 2 \f[I]poolset_file_src\f[] \- pathname of the pool \f[I]set\f[] file for the source pool set to be changed, .IP \[bu] 2 \f[I]poolset_file_dst\f[] \- pathname of the pool \f[I]set\f[] file that defines the new structure of the pool set, .IP \[bu] 2 \f[I]flags\f[] \- a combination of flags (ORed) which modify how synchronization is performed. .PP The following flags are available: .IP \[bu] 2 \f[B]PMEMPOOL_DRY_RUN\f[] \- do not apply changes, only check for viability of transformation. .PP When adding or deleting replicas, the two pool set files can differ only in the definitions of replicas which are to be added or deleted. When adding or removing pool set options (see \f[B]poolset\f[](5)), the rest of both pool set files have to be of the same structure. The operation of adding/removing a pool set option can be performed on a pool set with local replicas only. To add/remove a pool set option to/from a pool set with remote replicas, one has to remove the remote replicas first, then add/remove the option, and finally recreate the remote replicas having added/removed the pool set option to/from the remote replicas' poolset files. To add a replica it is necessary for its effective size to match or exceed the pool size. Otherwise the whole operation fails and no changes are applied. If none of the pool set options is used, the effective size of a replica is the sum of sizes of all its part files decreased by 4096 bytes per each part file. The 4096 bytes of each part file is utilized for storing internal metadata of the pool part files. If the option \f[I]SINGLEHDR\f[] is used, the effective size of a replica is the sum of sizes of all its part files decreased once by 4096 bytes. In this case only the first part contains internal metadata. If the option \f[I]NOHDRS\f[] is used, the effective size of a replica is the sum of sizes of all its part files. In this case none of the parts contains internal metadata. .SH RETURN VALUE .PP \f[B]pmempool_sync\f[]() and \f[B]pmempool_transform\f[]() return 0 on success. Otherwise, they return \-1 and set \f[I]errno\f[] appropriately. .SH NOTES .PP The \f[B]pmempool_sync\f[]() API is experimental and it may change in future versions of the library. .PP The \f[B]pmempool_transform\f[]() API is experimental and it may change in future versions of the library. .SH SEE ALSO .PP \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pmempool_transform.3000066400000000000000000000000241331545616200211640ustar00rootroot00000000000000.so pmempool_sync.3 pmdk-1.4.1/doc/generated/pobj_alloc.3000066400000000000000000000000241331545616200173450ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pobj_first.3000066400000000000000000000000241331545616200174020ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_first_type_num.3000066400000000000000000000000241331545616200213220ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_foreach.3000066400000000000000000000000241331545616200176620ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_foreach_safe.3000066400000000000000000000000241331545616200206600ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_foreach_safe_type.3000066400000000000000000000000241331545616200217210ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_foreach_type.3000066400000000000000000000000241331545616200207230ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_free.3000066400000000000000000000000241331545616200171740ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pobj_layout_begin.3000066400000000000000000000113101331545616200207340ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "POBJ_LAYOUT_BEGIN" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]POBJ_LAYOUT_BEGIN\f[](), \f[B]POBJ_LAYOUT_TOID\f[](), \f[B]POBJ_LAYOUT_ROOT\f[](), \f[B]POBJ_LAYOUT_NAME\f[](), \f[B]POBJ_LAYOUT_END\f[](), \f[B]POBJ_LAYOUT_TYPES_NUM\f[]() \[en] persistent memory transactional object store layout .SH SYNOPSIS .IP .nf \f[C] #include\ POBJ_LAYOUT_BEGIN(layout) POBJ_LAYOUT_TOID(layout,\ TYPE) POBJ_LAYOUT_ROOT(layout,\ ROOT_TYPE) POBJ_LAYOUT_NAME(layout) POBJ_LAYOUT_END(layout) POBJ_LAYOUT_TYPES_NUM(layout) \f[] .fi .SH DESCRIPTION .PP \f[B]libpmemobj\f[](7) defines a set of macros for convenient declaration of a pool's layout. The layout declaration consists of declarations of a number of used types. The declared types will be assigned consecutive type numbers. Declared types may be used in conjunction with type safety macros (see \f[B]TOID_DECLARE\f[](3)). Once created, the layout declaration must not be changed unless any new types are added at the end of the existing layout declaration. Modifying any existing declaration may lead to changes in the type numbers of declared types, which in consequence may cause data corruption. .PP The \f[B]POBJ_LAYOUT_BEGIN\f[]() macro indicates a begin of declaration of layout. The \f[I]LAYOUT\f[] argument is a name of layout. This argument must be passed to all macros related to the declaration of layout. .PP The \f[B]POBJ_LAYOUT_TOID\f[]() macro declares a typed \f[I]OID\f[] for type passed as \f[I]TYPE\f[] argument inside the declaration of layout. All types declared using this macro are assigned with consecutive type numbers. This macro must be used between the \f[B]POBJ_LAYOUT_BEGIN\f[]() and \f[B]POBJ_LAYOUT_END\f[]() macros, with the same name passed as \f[I]LAYOUT\f[] argument. .PP The \f[B]POBJ_LAYOUT_ROOT\f[]() macro declares a typed \f[I]OID\f[] for type passed as \f[I]ROOT_TYPE\f[] argument inside the declaration of layout. The typed \f[I]OID\f[] will be assigned with type number for root object \f[B]POBJ_ROOT_TYPE_NUM\f[]. .PP The \f[B]POBJ_LAYOUT_END\f[]() macro ends the declaration of layout. .PP The \f[B]POBJ_LAYOUT_NAME\f[]() macro returns the name of layout as a null\-terminated string. .PP The \f[B]POBJ_LAYOUT_TYPES_NUM\f[]() macro returns number of types declared using the \f[B]POBJ_LAYOUT_TOID\f[]() macro within the layout declaration. .SH EXAMPLE .PP This is an example of layout declaration: .IP .nf \f[C] POBJ_LAYOUT_BEGIN(mylayout); POBJ_LAYOUT_ROOT(mylayout,\ struct\ root); POBJ_LAYOUT_TOID(mylayout,\ struct\ node); POBJ_LAYOUT_TOID(mylayout,\ struct\ foo); POBJ_LAYOUT_END(mylayout); struct\ root { \ \ \ \ TOID(struct\ node)\ node; }; struct\ node { \ \ \ \ TOID(struct\ node)\ next; \ \ \ \ TOID(struct\ foo)\ foo; }; \f[] .fi .PP The name of layout and the number of declared types can be retrieved using the following code: .IP .nf \f[C] const\ char\ *layout_name\ =\ POBJ_LAYOUT_NAME(mylayout); int\ num_of_types\ =\ POBJ_LAYOUT_TYPES_NUM(mylayout); \f[] .fi .SH SEE ALSO .PP \f[B]TOID_DECLARE\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pobj_layout_end.3000066400000000000000000000000301331545616200204130ustar00rootroot00000000000000.so pobj_layout_begin.3 pmdk-1.4.1/doc/generated/pobj_layout_name.3000066400000000000000000000000301331545616200205650ustar00rootroot00000000000000.so pobj_layout_begin.3 pmdk-1.4.1/doc/generated/pobj_layout_root.3000066400000000000000000000000301331545616200206300ustar00rootroot00000000000000.so pobj_layout_begin.3 pmdk-1.4.1/doc/generated/pobj_layout_toid.3000066400000000000000000000000301331545616200206040ustar00rootroot00000000000000.so pobj_layout_begin.3 pmdk-1.4.1/doc/generated/pobj_layout_types_num.3000066400000000000000000000000301331545616200216700ustar00rootroot00000000000000.so pobj_layout_begin.3 pmdk-1.4.1/doc/generated/pobj_list_empty.3000066400000000000000000000000251331545616200204450ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_entry.3000066400000000000000000000000251331545616200204500ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_first.3000066400000000000000000000000251331545616200204360ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_foreach.3000066400000000000000000000000251331545616200207160ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_foreach_reverse.3000066400000000000000000000000251331545616200224510ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_head.3000066400000000000000000000313621331545616200202200ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "POBJ_LIST_HEAD" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]POBJ_LIST_HEAD\f[](), \f[B]POBJ_LIST_ENTRY\f[](), \f[B]POBJ_LIST_FIRST\f[](), \f[B]POBJ_LIST_LAST\f[](), \f[B]POBJ_LIST_EMPTY\f[](), \f[B]POBJ_LIST_NEXT\f[](), \f[B]POBJ_LIST_PREV\f[](), .PP \f[B]POBJ_LIST_FOREACH\f[](), \f[B]POBJ_LIST_FOREACH_REVERSE\f[](), .PP \f[B]POBJ_LIST_INSERT_HEAD\f[](), \f[B]POBJ_LIST_INSERT_TAIL\f[](), \f[B]POBJ_LIST_INSERT_AFTER\f[](), \f[B]POBJ_LIST_INSERT_BEFORE\f[](), \f[B]POBJ_LIST_INSERT_NEW_HEAD\f[](), \f[B]POBJ_LIST_INSERT_NEW_TAIL\f[](), \f[B]POBJ_LIST_INSERT_NEW_AFTER\f[](), \f[B]POBJ_LIST_INSERT_NEW_BEFORE\f[](), .PP \f[B]POBJ_LIST_REMOVE\f[](), \f[B]POBJ_LIST_REMOVE_FREE\f[](), .PP \f[B]POBJ_LIST_MOVE_ELEMENT_HEAD\f[](), \f[B]POBJ_LIST_MOVE_ELEMENT_TAIL\f[](), \f[B]POBJ_LIST_MOVE_ELEMENT_AFTER\f[](), \f[B]POBJ_LIST_MOVE_ELEMENT_BEFORE\f[]() \[en] type\-safe non\-transactional persistent atomic lists .SH SYNOPSIS .IP .nf \f[C] #include\ POBJ_LIST_HEAD(HEADNAME,\ TYPE) POBJ_LIST_ENTRY(TYPE) POBJ_LIST_FIRST(POBJ_LIST_HEAD\ *head) POBJ_LIST_LAST(POBJ_LIST_HEAD\ *head,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_EMPTY(POBJ_LIST_HEAD\ *head) POBJ_LIST_NEXT(TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_PREV(TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_FOREACH(TOID\ var,\ POBJ_LIST_HEAD\ *head,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_FOREACH_REVERSE(TOID\ var,\ POBJ_LIST_HEAD\ *head,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_INSERT_HEAD(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_INSERT_TAIL(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_INSERT_AFTER(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ listelm,\ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_INSERT_BEFORE(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ listelm,\ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_INSERT_NEW_HEAD(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ POBJ_LIST_ENTRY\ FIELD,\ size_t\ size, \ \ \ \ pmemobj_constr\ constructor,\ void\ *arg) POBJ_LIST_INSERT_NEW_TAIL(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ POBJ_LIST_ENTRY\ FIELD,\ size_t\ size, \ \ \ \ pmemobj_constr\ constructor,\ void\ *arg) POBJ_LIST_INSERT_NEW_AFTER(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ listelm,\ POBJ_LIST_ENTRY\ FIELD,\ size_t\ size, \ \ \ \ pmemobj_constr\ constructor,\ void\ *arg) POBJ_LIST_INSERT_NEW_BEFORE(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ listelm,\ POBJ_LIST_ENTRY\ FIELD,\ size_t\ size, \ \ \ \ pmemobj_constr\ constructor,\ void\ *arg) POBJ_LIST_REMOVE(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_REMOVE_FREE(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD) POBJ_LIST_MOVE_ELEMENT_HEAD(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ POBJ_LIST_HEAD\ *head_new,\ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD, \ \ \ \ POBJ_LIST_ENTRY\ field_new) POBJ_LIST_MOVE_ELEMENT_TAIL(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ POBJ_LIST_HEAD\ *head_new,\ TOID\ elm,\ POBJ_LIST_ENTRY\ FIELD, \ \ \ \ POBJ_LIST_ENTRY\ field_new) POBJ_LIST_MOVE_ELEMENT_AFTER(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ POBJ_LIST_HEAD\ *head_new,\ TOID\ listelm,\ TOID\ elm, \ \ \ \ POBJ_LIST_ENTRY\ FIELD,\ POBJ_LIST_ENTRY\ field_new) POBJ_LIST_MOVE_ELEMENT_BEFORE(PMEMobjpool\ *pop,\ POBJ_LIST_HEAD\ *head, \ \ \ \ POBJ_LIST_HEAD\ *head_new,\ TOID\ listelm,\ TOID\ elm, \ \ \ \ POBJ_LIST_ENTRY\ FIELD,\ POBJ_LIST_ENTRY\ field_new) \f[] .fi .SH DESCRIPTION .PP The following macros define and operate on a type\-safe persistent atomic circular doubly linked list data structure that consist of a set of persistent objects of a well\-known type. Unlike the functions described in the previous section, these macros provide type enforcement by requiring declaration of type of the objects stored in given list, and not allowing mixing objects of different types in a single list. .PP The functionality and semantics of those macros is similar to circular queues defined in \f[B]queue\f[](3). .PP The majority of the macros must specify the handle to the memory pool \f[I]pop\f[] and the name of the \f[I]field\f[] in the user\-defined structure, which must be of type \f[I]POBJ_LIST_ENTRY\f[] and is used to connect the elements in the list. .PP A list is headed by a structure defined by the \f[B]POBJ_LIST_HEAD\f[]() macro. This structure contains an object handle of the first element on the list. The elements are doubly linked so that an arbitrary element can be removed without a need to traverse the list. New elements can be added to the list before or after an existing element, at the head of the list, or at the end of the list. A list may be traversed in either direction. A \f[I]POBJ_LIST_HEAD\f[] structure is declared as follows: .IP .nf \f[C] #define\ POBJ_LIST_HEAD(HEADNAME,\ TYPE) struct\ HEADNAME { \ \ \ \ TOID(TYPE)\ pe_first; \ \ \ \ PMEMmutex\ lock; }; \f[] .fi .PP In the macro definitions, \f[I]TYPE\f[] is the name of a user\-defined structure, that must contain a field of type \f[I]POBJ_LIST_ENTRY\f[]. The argument \f[I]HEADNAME\f[] is the name of a user\-defined structure that must be declared using the macro \f[I]POBJ_LIST_HEAD\f[]. See the examples below for further explanation of how these macros are used. .PP The macro \f[I]POBJ_LIST_ENTRY\f[] declares a structure that connects the elements in the list. .IP .nf \f[C] #define\ POBJ_LIST_ENTRY(TYPE) struct { \ \ \ \ TOID(TYPE)\ pe_next; \ \ \ \ TOID(TYPE)\ pe_prev; }; \f[] .fi .PP The macro \f[B]POBJ_LIST_FIRST\f[]() returns the first element on the list referenced by \f[I]head\f[]. If the list is empty \f[B]OID_NULL\f[] is returned. .PP The macro \f[B]POBJ_LIST_LAST\f[]() returns the last element on the list referenced by \f[I]head\f[]. If the list is empty \f[B]OID_NULL\f[] is returned. .PP The macro \f[B]POBJ_LIST_EMPTY\f[]() evaluates to 1 if the list referenced by \f[I]head\f[] is empty. Otherwise, 0 is returned. .PP The macro \f[B]POBJ_LIST_NEXT\f[]() returns the element next to the element \f[I]elm\f[]. .PP The macro \f[B]POBJ_LIST_PREV\f[]() returns the element preceding the element \f[I]elm\f[]. .PP The macro \f[B]POBJ_LIST_FOREACH\f[]() traverses the list referenced by \f[I]head\f[] assigning a handle to each element in turn to \f[I]var\f[] variable. .PP The macro \f[B]POBJ_LIST_FOREACH_REVERSE\f[]() traverses the list referenced by \f[I]head\f[] in reverse order, assigning a handle to each element in turn to \f[I]var\f[] variable. The \f[I]field\f[] argument is the name of the field of type \f[I]POBJ_LIST_ENTRY\f[] in the element structure. .PP The macro \f[B]POBJ_LIST_INSERT_HEAD\f[]() inserts the element \f[I]elm\f[] at the head of the list referenced by \f[I]head\f[]. .PP The macro \f[B]POBJ_LIST_INSERT_TAIL\f[]() inserts the element \f[I]elm\f[] at the end of the list referenced by \f[I]head\f[]. .PP The macro \f[B]POBJ_LIST_INSERT_AFTER\f[]() inserts the element \f[I]elm\f[] into the list referenced by \f[I]head\f[] after the element \f[I]listelm\f[]. If \f[I]listelm\f[] value is \f[B]TOID_NULL\f[], the object is inserted at the end of the list. .PP The macro \f[B]POBJ_LIST_INSERT_BEFORE\f[]() inserts the element \f[I]elm\f[] into the list referenced by \f[I]head\f[] before the element \f[I]listelm\f[]. If \f[I]listelm\f[] value is \f[B]TOID_NULL\f[], the object is inserted at the head of the list. .PP The macro \f[B]POBJ_LIST_INSERT_NEW_HEAD\f[]() atomically allocates a new object of size \f[I]size\f[] and inserts it at the head of the list referenced by \f[I]head\f[]. The newly allocated object is also added to the internal object container associated with a type number which is retrieved from the typed \f[I]OID\f[] of the first element on list. .PP The macro \f[B]POBJ_LIST_INSERT_NEW_TAIL\f[]() atomically allocates a new object of size \f[I]size\f[] and inserts it at the tail of the list referenced by \f[I]head\f[]. The newly allocated object is also added to the internal object container associated with with a type number which is retrieved from the typed \f[I]OID\f[] of the first element on list. .PP The macro \f[B]POBJ_LIST_INSERT_NEW_AFTER\f[]() atomically allocates a new object of size \f[I]size\f[] and inserts it into the list referenced by \f[I]head\f[] after the element \f[I]listelm\f[]. If \f[I]listelm\f[] value is \f[B]TOID_NULL\f[], the object is inserted at the end of the list. The newly allocated object is also added to the internal object container associated with with a type number which is retrieved from the typed \f[I]OID\f[] of the first element on list. .PP The macro \f[B]POBJ_LIST_INSERT_NEW_BEFORE\f[]() atomically allocates a new object of size \f[I]size\f[] and inserts it into the list referenced by \f[I]head\f[] before the element \f[I]listelm\f[]. If \f[I]listelm\f[] value is \f[B]TOID_NULL\f[], the object is inserted at the head of the list. The newly allocated object is also added to the internal object container associated with with a type number which is retrieved from the typed \f[I]OID\f[] of the first element on list. .PP The macro \f[B]POBJ_LIST_REMOVE\f[]() removes the element \f[I]elm\f[] from the list referenced by \f[I]head\f[]. .PP The macro \f[B]POBJ_LIST_REMOVE_FREE\f[]() removes the element \f[I]elm\f[] from the list referenced by \f[I]head\f[] and frees the memory space represented by this element. .PP The macro \f[B]POBJ_LIST_MOVE_ELEMENT_HEAD\f[]() moves the element \f[I]elm\f[] from the list referenced by \f[I]head\f[] to the head of the list \f[I]head_new\f[]. The \f[I]field\f[] and \f[I]field_new\f[] arguments are the names of the fields of type \f[I]POBJ_LIST_ENTRY\f[] in the element structure that are used to connect the elements in both lists. .PP The macro \f[B]POBJ_LIST_MOVE_ELEMENT_TAIL\f[]() moves the element \f[I]elm\f[] from the list referenced by \f[I]head\f[] to the end of the list \f[I]head_new\f[]. The \f[I]field\f[] and \f[I]field_new\f[] arguments are the names of the fields of type \f[I]POBJ_LIST_ENTRY\f[] in the element structure that are used to connect the elements in both lists. .PP The macro \f[B]POBJ_LIST_MOVE_ELEMENT_AFTER\f[]() atomically removes the element \f[I]elm\f[] from the list referenced by \f[I]head\f[] and inserts it into the list referenced by \f[I]head_new\f[] after the element \f[I]listelm\f[]. If \f[I]listelm\f[] value is \f[I]TOID_NULL\f[], the object is inserted at the end of the list. The \f[I]field\f[] and \f[I]field_new\f[] arguments are the names of the fields of type \f[I]POBJ_LIST_ENTRY\f[] in the element structure that are used to connect the elements in both lists. .PP The macro \f[B]POBJ_LIST_MOVE_ELEMENT_BEFORE\f[]() atomically removes the element \f[I]elm\f[] from the list referenced by \f[I]head\f[] and inserts it into the list referenced by \f[I]head_new\f[] before the element \f[I]listelm\f[]. If \f[I]listelm\f[] value is \f[B]TOID_NULL\f[], the object is inserted at the head of the list. The \f[I]field\f[] and \f[I]field_new\f[] arguments are the names of the fields of type \f[I]POBJ_LIST_ENTRY\f[] in the element structure that are used to connect the elements in both lists. .SH SEE ALSO .PP \f[B]queue\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/pobj_list_insert_after.3000066400000000000000000000000251331545616200217740ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_before.3000066400000000000000000000000251331545616200221350ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_head.3000066400000000000000000000000251331545616200215740ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_new_after.3000066400000000000000000000000251331545616200226450ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_new_before.3000066400000000000000000000000251331545616200230060ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_new_head.3000066400000000000000000000000251331545616200224450ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_new_tail.3000066400000000000000000000000251331545616200224750ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_insert_tail.3000066400000000000000000000000251331545616200216240ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_last.3000066400000000000000000000000251331545616200202520ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_move_element_after.3000066400000000000000000000000251331545616200231470ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_move_element_before.3000066400000000000000000000000251331545616200233100ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_move_element_head.3000066400000000000000000000000251331545616200227470ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_move_element_tail.3000066400000000000000000000000251331545616200227770ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_next.3000066400000000000000000000000251331545616200202650ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_prev.3000066400000000000000000000000251331545616200202630ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_remove.3000066400000000000000000000000251331545616200206040ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_list_remove_free.3000066400000000000000000000000251331545616200216050ustar00rootroot00000000000000.so pobj_list_head.3 pmdk-1.4.1/doc/generated/pobj_new.3000066400000000000000000000000241331545616200170440ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pobj_next.3000066400000000000000000000000241331545616200172310ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_next_type_num.3000066400000000000000000000000241331545616200211510ustar00rootroot00000000000000.so pmemobj_first.3 pmdk-1.4.1/doc/generated/pobj_realloc.3000066400000000000000000000000241331545616200176740ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pobj_reserve_alloc.3000066400000000000000000000000261331545616200211020ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pobj_reserve_new.3000066400000000000000000000000261331545616200206010ustar00rootroot00000000000000.so pmemobj_action.3 pmdk-1.4.1/doc/generated/pobj_root.3000066400000000000000000000000231331545616200172350ustar00rootroot00000000000000.so pmemobj_root.3 pmdk-1.4.1/doc/generated/pobj_zalloc.3000066400000000000000000000000241331545616200175370ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pobj_znew.3000066400000000000000000000000241331545616200172360ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/pobj_zrealloc.3000066400000000000000000000000241331545616200200660ustar00rootroot00000000000000.so pmemobj_alloc.3 pmdk-1.4.1/doc/generated/poolset.5000066400000000000000000000302771331545616200167450ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "POOLSET" "5" "2018-05-21" "PMDK - poolset API version 1.0" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP poolset \[en] persistent memory pool configuration file format .SH SYNOPSIS .IP .nf \f[C] mypool.set \f[] .fi .SH DESCRIPTION .PP Depending on the configuration of the system, the available non\-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the transactional object store could be limited by the capacity of a single memory device. Therefore, \f[B]libpmemobj\f[](7), \f[B]libpmemblk\f[](7) and \f[B]libpmemlog\f[](7) allow building object stores spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a \f[I]pool set\f[] may be stored on a different pmem\-aware filesystem. .PP To improve reliability and eliminate single point of failure, \f[B]libpmemobj\f[](7) also allows all the data written to a persistent memory pool to be copied to local or remote pool \f[I]replicas\f[], thereby providing backup for the persistent memory pool by producing a \f[I]mirrored pool set\f[]. In practice, the pool replicas may be considered as binary copies of the \[lq]master\[rq] pool set. Data replication is not supported in \f[B]libpmemblk\f[](7) and \f[B]libpmemlog\f[](7). .PP The \f[I]set\f[] file for each type of pool is a plain text file. Lines in the file are formatted as follows: .IP \[bu] 2 The first line of the file must be the literal string \[lq]PMEMPOOLSET\[rq] .IP \[bu] 2 The pool parts are specified, one per line, in the format: .RS 2 .PP \f[I]size\f[] \f[I]pathname\f[] .RE .IP \[bu] 2 \f[I]Replica\f[] sections, if any, start with the literal string \[lq]REPLICA\[rq]. See \f[B]REPLICAS\f[], below, for further details. .IP \[bu] 2 Pool set options, if any, start with literal string \f[I]OPTION\f[]. See \f[B]POOL SET OPTIONS\f[] below for details. .IP \[bu] 2 Lines starting with \[lq]#\[rq] are considered comments and are ignored. .PP The \f[I]size\f[] must be compliant with the format specified in IEC 80000\-13, IEEE 1541 or the Metric Interchange Format. These standards accept SI units with obligatory B \- kB, MB, GB, \&... (multiplier by 1000) suffixes, and IEC units with optional \[lq]iB\[rq] \- KiB, MiB, GiB, \&..., K, M, G, \&... \- (multiplier by 1024) suffixes. .PP \f[I]pathname\f[] must be an absolute pathname. .PP The \f[I]pathname\f[] of a part can point to a Device DAX. Device DAX is the device\-centric analogue of Filesystem DAX. It allows memory ranges to be allocated and mapped without need of an intervening file system. .PP Pools created on Device DAX have additional options and restrictions: .IP \[bu] 2 The \f[I]size\f[] may be set to \[lq]AUTO\[rq], in which case the size of the device will be automatically resolved at pool creation time. .IP \[bu] 2 To concatenate more than one Device DAX device into a single pool set, the configured internal alignment of the devices must be 4KiB, unless the \f[I]SINGLEHDR\f[] or \f[I]NOHDRS\f[] option is used in the pool set file. See \f[B]POOL SET OPTIONS\f[] below for details. .PP Please see \f[B]ndctl\-create\-namespace\f[](1) for more information on Device DAX, including how to configure desired alignment. .PP The minimum file size of each part of the pool set is defined as follows: .IP \[bu] 2 For block pools, as \f[B]PMEMBLK_MIN_PART\f[] in \f[B]\f[] .IP \[bu] 2 For object pools, as \f[B]PMEMOBJ_MIN_PART\f[] in \f[B]\f[] .IP \[bu] 2 For log pools, as \f[B]PMEMLOG_MIN_PART\f[] in \f[B]\f[] .PP The net pool size of the pool set is equal to: .IP .nf \f[C] net_pool_size\ =\ sum_over_all_parts(page_aligned_part_size\ \-\ 4KiB)\ +\ 4KiB \f[] .fi .PP where .IP .nf \f[C] page_aligned_part_size\ =\ part_size\ &\ ~(page_size\ \-\ 1) \f[] .fi .PP Note that page size is OS specific. For more information please see \f[B]sysconf\f[](3). .PP The minimum net pool size of a pool set is defined as follows: .IP \[bu] 2 For block pools, as \f[B]PMEMBLK_MIN_POOL\f[] in \f[B]\f[] .IP \[bu] 2 For object pools, as \f[B]PMEMOBJ_MIN_POOL\f[] in \f[B]\f[] .IP \[bu] 2 For log pools, as \f[B]PMEMLOG_MIN_POOL\f[] in \f[B]\f[] .PP Here is an example \[lq]mypool.set\[rq] file: .IP .nf \f[C] PMEMPOOLSET OPTION\ NOHDRS 100G\ /mountpoint0/myfile.part0 200G\ /mountpoint1/myfile.part1 400G\ /mountpoint2/myfile.part2 \f[] .fi .PP The files in the set may be created by running one of the following commands. To create a block pool: .IP .nf \f[C] $\ pmempool\ create\ blk\ \ mypool.set \f[] .fi .PP To create a log pool: .IP .nf \f[C] $\ pmempool\ create\ log\ mypool.set \f[] .fi .SH REPLICAS .PP Sections defining replica sets are optional. There may be multiple replica sections. .PP Local replica sections begin with a line containing only the literal string \[lq]REPLICA\[rq], followed by one or more pool part lines as described above. .PP Remote replica sections consist of the \f[I]REPLICA\f[] keyword, followed on the same line by the address of a remote host and a relative path to a remote pool set file: .IP .nf \f[C] REPLICA\ [\@]\ [/] \f[] .fi .IP \[bu] 2 \f[I]hostname\f[] must be in the format recognized by the \f[B]ssh\f[](1) remote login client .IP \[bu] 2 \f[I]pathname\f[] is relative to the root config directory on the target node \- see \f[B]librpmem\f[](3) .PP There are no other lines in the remote replica section \- the REPLICA line defines a remote replica entirely. .PP Here is an example \[lq]myobjpool.set\[rq] file with replicas: .IP .nf \f[C] PMEMPOOLSET 100G\ /mountpoint0/myfile.part0 200G\ /mountpoint1/myfile.part1 400G\ /mountpoint2/myfile.part2 #\ local\ replica REPLICA 500G\ /mountpoint3/mymirror.part0 200G\ /mountpoint4/mymirror.part1\ #\ remote\ replica REPLICA\ user\@example.com\ remote\-objpool.set \f[] .fi .PP The files in the object pool set may be created by running the following command: .IP .nf \f[C] $\ pmempool\ create\ \-\-layout="mylayout"\ obj\ myobjpool.set \f[] .fi .PP Remote replica cannot have replicas, i.e.\ a remote pool set file cannot define any replicas. .SH POOL SET OPTIONS .PP Pool set options can appear anywhere after the line with \f[I]PMEMPOOLSET\f[] string. Pool set file can contain several pool set options. The following options are supported: .IP \[bu] 2 \f[I]SINGLEHDR\f[] .IP \[bu] 2 \f[I]NOHDRS\f[] .PP If the \f[I]SINGLEHDR\f[] option is used, only the first part in each replica contains the pool part internal metadata. In that case the effective size of a replica is the sum of sizes of all its part files decreased once by 4096 bytes. .PP The \f[I]NOHDRS\f[] option can appear only in the remote pool set file, when \f[B]librpmem\f[] does not serve as a means of replication for \f[B]libpmemobj\f[] pool. In that case none of the pool parts contains internal metadata. The effective size of such a replica is the sum of sizes of all its part files. .PP Options \f[I]SINGLEHDR\f[] and \f[I]NOHDRS\f[] are mutually exclusive. If both are specified in a pool set file, creating or opening the pool will fail with an error. .PP When using the \f[I]SINGLEHDR\f[] or \f[I]NOHDRS\f[] option, one can concatenate more than one Device DAX devices with any internal alignments in one replica. .PP The \f[I]SINGLEHDR\f[] option concerns only replicas that are local to the pool set file. That is if one wants to create a pool set with the \f[I]SINGLEHDR\f[] option and with remote replicas, one has to add this option to the local pool set file as well as to every single remote pool set file. .PP Using the \f[I]SINGLEHDR\f[] and \f[I]NOHDRS\f[] options has important implications for data integrity checking and recoverability in case of a pool set damage. See \f[B]pmempool_sync\f[]() API for more information about pool set recovery. .SH DIRECTORIES .PP Providing a directory as a part's \f[I]pathname\f[] allows the pool to dynamically create files and consequently removes the user\-imposed limit on the size of the pool. .PP The \f[I]size\f[] argument of a part in a directory poolset becomes the size of the address space reservation required for the pool. In other words, the size argument is the maximum theoretical size of the mapping. This value can be freely increased between instances of the application, but decreasing it below the real required space will result in an error when attempting to open the pool. .PP The directory must NOT contain user created files with extension \f[I].pmem\f[], otherwise the behavior is undefined. If a file created by the library within the directory is in any way altered (resized, renamed) the behavior is undefined. .PP A directory poolset must exclusively use directories to specify paths \- combining files and directories will result in an error. A single replica can consist of one or more directories. If there are multiple directories, the address space reservation is equal to the sum of the sizes. .PP The order in which the files are created is unspecified, but the library will try to maintain equal usage of the directories. .PP By default pools grow in 128 megabyte increments. .PP Only poolsets with the \f[I]SINGLEHDR\f[] option can safely use directories. .SH NOTES .PP Creation of all the parts of the pool set and the associated replica sets can be done with the \f[B]pmemobj_create\f[](3), \f[B]pmemblk_create\f[](3) or \f[B]pmemlog_create\f[](3) function, or by using the \f[B]pmempool\f[](1) utility. .PP Restoring data from a local or remote replica can be done by using the \f[B]pmempool\-sync\f[](1) command or the \f[B]pmempool_sync\f[]() API from the \f[B]libpmempool\f[](3) library. .PP Modifications of a pool set file configuration can be done by using the \f[B]pmempool\-transform\f[](1) command or the \f[B]pmempool_transform\f[]() API from the \f[B]libpmempool\f[](3) library. .PP When creating a pool set consisting of multiple files, or when creating a replicated pool set, the \f[I]path\f[] argument passed to \f[B]pmemobj_create\f[](3), \f[B]pmemblk_create\f[](3) or \f[B]pmemlog_create\f[](3) must point to the special \f[I]set\f[] file that defines the pool layout and the location of all the parts of the pool set. .PP When opening a pool set consisting of multiple files, or when opening a replicated pool set, the \f[I]path\f[] argument passed to \f[B]pmemobj_open\f[](3), \f[B]pmemblk_open\f[](3) or \f[B]pmemlog_open\f[](3) must point to the same \f[I]set\f[] file that was used for pool set creation. .SH SEE ALSO .PP \f[B]ndctl\-create\-namespace\f[](1), \f[B]pmemblk_create\f[](3), \f[B]pmemlog_create\f[](3), \f[B]pmemobj_create\f[](3), \f[B]sysconf\f[](3), \f[B]libpmemblk\f[](7), \f[B]libpmemlog\f[](7), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/rpmem_check_version.3000066400000000000000000000000241331545616200212630ustar00rootroot00000000000000.so man7/librpmem.7 pmdk-1.4.1/doc/generated/rpmem_close.3000066400000000000000000000000231331545616200175450ustar00rootroot00000000000000.so rpmem_create.3 pmdk-1.4.1/doc/generated/rpmem_create.3000066400000000000000000000240511331545616200177120ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "RPMEM_CREATE" "3" "2018-05-21" "PMDK - rpmem API version 1.2" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]rpmem_create\f[](), \f[B]rpmem_open\f[](), \f[B]rpmem_set_attr\f[](), \f[B]rpmem_close\f[](), \f[B]rpmem_remove\f[]() \[en] most commonly used functions for remote access to \f[I]persistent memory\f[] .SH SYNOPSIS .IP .nf \f[C] #include\ RPMEMpool\ *rpmem_create(const\ char\ *target,\ const\ char\ *pool_set_name, \ \ \ \ void\ *pool_addr,\ size_t\ pool_size,\ unsigned\ *nlanes, \ \ \ \ const\ struct\ rpmem_pool_attr\ *create_attr); RPMEMpool\ *rpmem_open(const\ char\ *target,\ const\ char\ *pool_set_name, \ \ \ \ void\ *pool_addr,\ size_t\ pool_size,\ unsigned\ *nlanes, \ \ \ \ struct\ rpmem_pool_attr\ *open_attr); int\ rpmem_set_attr(RPMEMpool\ *rpp,\ const\ struct\ rpmem_pool_attr\ *attr); int\ rpmem_close(RPMEMpool\ *rpp); int\ rpmem_remove(const\ char\ *target,\ const\ char\ *pool_set_name,\ int\ flags); \f[] .fi .SH DESCRIPTION .PP The \f[B]rpmem_create\f[]() function creates a remote pool on a given \f[I]target\f[] node, using pool \f[I]set\f[] file \f[I]pool_set_name\f[] to map the remote pool. \f[I]pool_set_name\f[] is a relative path in the root config directory on the \f[I]target\f[] node. For pool set file format and options see \f[B]poolset\f[](5). \f[I]pool_addr\f[] is a pointer to the associated local memory pool with size \f[I]pool_size\f[]. Both \f[I]pool_addr\f[] and \f[I]pool_size\f[] must be aligned to the system's page size (see \f[B]sysconf\f[](3)). The size of the remote pool must be at least \f[I]pool_size\f[]. See \f[B]REMOTE POOL SIZE\f[], below, for details. \f[I]nlanes\f[] points to the maximum number of lanes which the caller is requesting. Upon successful creation of the remote pool, *\f[I]nlanes\f[] is set to the maximum number of lanes supported by both the local and remote nodes. See \f[B]LANES\f[], below, for details. The \f[I]create_attr\f[] structure contains the attributes used for creating the remote pool. If the \f[I]create_attr\f[] structure is not NULL, a pool with internal metadata is created. The metadata is stored in the first 4096 bytes of the pool and can be read when opening the remote pool with \f[B]rpmem_open\f[](). To prevent user from overwriting the pool metadata, this region is not accessible to the user via \f[B]rpmem_persist\f[](). If \f[I]create_attr\f[] is NULL or zeroed, remote pool set file must contain the \f[I]NOHDRS\f[] option. In that case the remote pool is created without internal metadata in it and the entire pool space is available to the user. See \f[B]rpmem_persist\f[](3) for details. .PP The \f[B]rpmem_open\f[]() function opens the existing remote pool with \f[I]set\f[] file \f[I]pool_set_name\f[] on remote node \f[I]target\f[]. \f[I]pool_set_name\f[] is a relative path in the root config directory on the \f[I]target\f[] node. \f[I]pool_addr\f[] is a pointer to the associated local memory pool of size \f[I]pool_size\f[]. Both \f[I]pool_addr\f[] and \f[I]pool_size\f[] must be aligned to the system's page size (see \f[B]sysconf\f[](3)). The size of the remote pool must be at least \f[I]pool_size\f[]. See \f[B]REMOTE POOL SIZE\f[], below, for details. \f[I]nlanes\f[] points to the maximum number of lanes which the caller is requesting. Upon successful opening of the remote pool, *\f[I]nlanes\f[] is set to the maximum number of lanes supported by both the local and remote nodes. See \f[B]LANES\f[], below, for details. .PP The \f[B]rpmem_set_attr\f[]() function overwrites the pool's attributes. The \f[I]attr\f[] structure contains the attributes used for overwriting the remote pool attributes that were passed to \f[B]rpmem_create\f[]() at pool creation. If \f[I]attr\f[] is NULL, a zeroed structure with attributes will be used. New attributes are stored in the pool's metadata. .PP The \f[B]rpmem_close\f[]() function closes the remote pool \f[I]rpp\f[]. All resources are released on both the local and remote nodes. The remote pool itself persists on the remote node and may be re\-opened at a later time using \f[B]rpmem_open\f[](). .PP The \f[B]rpmem_remove\f[]() function removes the remote pool with \f[I]set\f[] file name \f[I]pool_set_name\f[] from node \f[I]target\f[]. The \f[I]pool_set_name\f[] is a relative path in the root config directory on the \f[I]target\f[] node. By default only the pool part files are removed; the pool \f[I]set\f[] file is left untouched. If the pool is not consistent, the \f[B]rpmem_remove\f[]() function fails. The \f[I]flags\f[] argument determines the behavior of \f[B]rpmem_remove\f[](). \f[I]flags\f[] may be either 0 or the bitwise OR of one or more of the following flags: .IP \[bu] 2 \f[B]RPMEM_REMOVE_FORCE\f[] \- Ignore errors when opening an inconsistent pool. The pool \f[I]set\f[] file must still be in appropriate format for the pool to be removed. .IP \[bu] 2 \f[B]RPMEM_REMOVE_POOL_SET\f[] \- Remove the pool \f[I]set\f[] file after removing the pool described by this pool set. .SH RETURN VALUE .PP On success, \f[B]rpmem_create\f[]() returns an opaque handle to the remote pool for use in subsequent \f[B]librpmem\f[] calls. If any error prevents the remote pool from being created, \f[B]rpmem_create\f[]() returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]rpmem_open\f[]() returns an opaque handle to the remote pool for subsequent \f[B]librpmem\f[] calls. If the \f[I]open_attr\f[] argument is not NULL, the remote pool attributes are returned in the provided structure. If the remote pool was created without internal metadata, zeroes are returned in the \f[I]open_attr\f[] structure on successful call to \f[B]rpmem_open\f[](). If any error prevents the remote pool from being opened, \f[B]rpmem_open\f[]() returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]rpmem_set_attr\f[]() returns 0. On error, it returns \-1 and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]rpmem_close\f[]() returns 0. On error, it returns a non\-zero value and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]rpmem_remove\f[]() returns 0. On error, it returns a non\-zero value and sets \f[I]errno\f[] appropriately. .SH NOTES .SS REMOTE POOL SIZE .PP The size of a remote pool depends on the configuration in the pool set file on the remote node (see \f[B]poolset\f[](5)). If no pool set options is used in the remote pool set file, the remote pool size is the sum of the sizes of all part files, decreased by 4096 bytes per part file. 4096 bytes of each part file are utilized for storing internal metadata. If the \f[I]SINGLEHDR\f[] option is used in the remote pool set file, the remote pool size is the sum of sizes of all part files, decreased once by 4096 bytes. In this case only the first part contains internal metadata. If a remote pool set file contains the \f[I]NOHDRS\f[] option, the remote pool size is the sum of sizes of all its part files. In this case none of the parts contains internal metadata. For other consequences of using the \f[I]SINGLEHDR\f[] and \f[I]NOHDRS\f[] options see \f[B]rpmem_persist\f[](3). \f[B]RPMEM_MIN_PART\f[] and \f[B]RPMEM_MIN_POOL\f[] in \f[B]\f[] define the minimum size allowed by \f[B]librpmem\f[] for a part file and a remote pool, respectively. .SS LANES .PP The term \f[I]lane\f[] means an isolated path of execution. The underlying hardware utilized by both local and remote nodes may have limited resources that restrict the maximum number of parallel \f[B]rpmem_persist\f[](3) operations. The maximum number of supported lanes is returned by the \f[B]rpmem_open\f[]() and \f[B]rpmem_create\f[]() function calls. The caller passes the maximum number of lanes requested in *\f[I]nlanes\f[]. If the pool is successfully created or opened, *\f[I]nlanes\f[] is updated to reflect the minimum of the number of lanes requested by the caller and the maximum number of lanes supported by underlying hardware. The application is obligated to use at most the returned number of lanes in parallel. .PP \f[B]rpmem_persist\f[](3) does not provide any locking mechanism; thus any serialization of calls must be performed by the application if required. .PP Each lane requires a separate connection, represented by a file descriptor. If the system runs out of free file descriptors during \f[B]rpmem_create\f[]() or \f[B]rpmem_open\f[](), these functions will fail. See \f[B]nofile\f[] in \f[B]limits.conf\f[](5) for more details. .SH SEE ALSO .PP \f[B]rpmem_persist\f[](3), \f[B]sysconf\f[](3), \f[B]limits.conf\f[](5), \f[B]libpmemobj\f[](7), \f[B]librpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/rpmem_deep_persist.3000066400000000000000000000000241331545616200211270ustar00rootroot00000000000000.so rpmem_persist.3 pmdk-1.4.1/doc/generated/rpmem_errormsg.3000066400000000000000000000000241331545616200203010ustar00rootroot00000000000000.so man7/librpmem.7 pmdk-1.4.1/doc/generated/rpmem_open.3000066400000000000000000000000231331545616200174010ustar00rootroot00000000000000.so rpmem_create.3 pmdk-1.4.1/doc/generated/rpmem_persist.3000066400000000000000000000116001331545616200201340ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "RPMEM_PERSIST" "3" "2018-05-21" "PMDK - rpmem API version 1.2" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]rpmem_persist\f[](), \f[B]rpmem_read\f[](), \[en] functions to copy and read remote pools .SH SYNOPSIS .IP .nf \f[C] #include\ int\ rpmem_persist(RPMEMpool\ *rpp,\ size_t\ offset, \ \ \ \ size_t\ length,\ unsigned\ lane); int\ rpmem_deep_persist(RPMEMpool\ *rpp,\ size_t\ offset, \ \ \ \ size_t\ length,\ unsigned\ lane); int\ rpmem_read(RPMEMpool\ *rpp,\ void\ *buff,\ size_t\ offset, \ \ \ \ size_t\ length,\ unsigned\ lane); \f[] .fi .SH DESCRIPTION .PP The \f[B]rpmem_persist\f[]() function copies data of given \f[I]length\f[] at given \f[I]offset\f[] from the associated local memory pool and makes sure the data is persistent on the remote node before the function returns. The remote node is identified by the \f[I]rpp\f[] handle which must be returned from either \f[B]rpmem_open\f[](3) or \f[B]rpmem_create\f[](3). The \f[I]offset\f[] is relative to the \f[I]pool_addr\f[] specified in the \f[B]rpmem_open\f[](3) or \f[B]rpmem_create\f[](3) call. If the remote pool was created using \f[B]rpmem_create\f[]() with non\-NULL \f[I]create_attr\f[] argument, \f[I]offset\f[] has to be greater or equal to 4096. In that case the first 4096 bytes of the pool is used for storing the pool matadata and cannot be overwritten. If the pool was created with NULL \f[I]create_attr\f[] argument, the pool metadata is not stored with the pool and \f[I]offset\f[] can be any nonnegative number. The \f[I]offset\f[] and \f[I]length\f[] combined must not exceed the \f[I]pool_size\f[] passed to \f[B]rpmem_open\f[](3) or \f[B]rpmem_create\f[](3). The \f[B]rpmem_persist\f[]() operation is performed using the given \f[I]lane\f[] number. The lane must be less than the value returned by \f[B]rpmem_open\f[](3) or \f[B]rpmem_create\f[](3) through the \f[I]nlanes\f[] argument (so it can take a value from 0 to \f[I]nlanes\f[] \- 1). .PP The \f[B]rpmem_deep_persist\f[]() function works in the same way as \f[B]rpmem_persist\f[](3) function, but additionaly it flushes the data to the lowest possible persistency domain available from software. Please see \f[B]pmem_deep_persist\f[](3) for details. .PP The \f[B]rpmem_read\f[]() function reads \f[I]length\f[] bytes of data from a remote pool at \f[I]offset\f[] and copies it to the buffer \f[I]buff\f[]. The operation is performed on the specified \f[I]lane\f[]. The lane must be less than the value returned by \f[B]rpmem_open\f[](3) or \f[B]rpmem_create\f[](3) through the \f[I]nlanes\f[] argument (so it can take a value from 0 to \f[I]nlanes\f[] \- 1). The \f[I]rpp\f[] must point to a remote pool opened or created previously by \f[B]rpmem_open\f[](3) or \f[B]rpmem_create\f[](3). .SH RETURN VALUE .PP The \f[B]rpmem_persist\f[]() function returns 0 if the entire memory area was made persistent on the remote node. Otherwise it returns a non\-zero value and sets \f[I]errno\f[] appropriately. .PP The \f[B]rpmem_read\f[]() function returns 0 if the data was read entirely. Otherwise it returns a non\-zero value and sets \f[I]errno\f[] appropriately. .SH SEE ALSO .PP \f[B]rpmem_create\f[](3), \f[B]rpmem_open\f[](3), \f[B]rpmem_persist\f[](3), \f[B]sysconf\f[](3), \f[B]limits.conf\f[](5), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/rpmem_read.3000066400000000000000000000000241331545616200173540ustar00rootroot00000000000000.so rpmem_persist.3 pmdk-1.4.1/doc/generated/rpmem_remove.3000066400000000000000000000000211331545616200177330ustar00rootroot00000000000000.so rpmem_open.3 pmdk-1.4.1/doc/generated/rpmem_set_attr.3000066400000000000000000000000231331545616200202650ustar00rootroot00000000000000.so rpmem_create.3 pmdk-1.4.1/doc/generated/rpmemd.1000066400000000000000000000207401331545616200165320ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "RPMEMD" "1" "2018-05-21" "PMDK - rpmemd version 1.4" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]rpmemd\f[] \[en] librpmem target node process (EXPERIMENTAL) .SH SYNOPSIS .IP .nf \f[C] $\ rpmemd\ [\-\-help]\ [\-\-version]\ [] \f[] .fi .SH DESCRIPTION .PP The \f[B]rpmemd\f[] process is executed on target node by \f[B]librpmem\f[](7) library over \f[B]ssh\f[](1) and facilitates access to persistent memory over RDMA. The \f[B]rpmemd\f[] should not be run manually under normal conditions. .SH OPTIONS .PP Command line options overwrite the default \f[B]rpmemd\f[] configuration, the global configuration file and the user configuration file. .PP \f[C]\-V,\ \-\-version\f[] .PP Displays \f[B]rpmemd\f[] version and exits. .PP \f[C]\-h,\ \-\-help\f[] .PP Prints synopsis and list of parameters and exits. .PP \f[C]\-c,\ \-\-config\ \f[] .PP Custom configuration file location. If the custom configuration file is provided others are omitted. See \f[B]CONFIGURATION FILES\f[] section for details. .PP All options described in \f[B]CONFIGURATION FILES\f[] section are common for both the configuration file and the command line \- the equivalent of the following line in the config file: .PP \f[C]option\ =\ value\f[] .PP is .PP \f[C]\-\-option\ value\f[] .PP in the command line. .PP The following command line options: \f[B]\[en]persist\-apm\f[], \f[B]\[en]persist\-general\f[] and \f[B]\[en]use\-syslog\f[] should not be followed by any value. Presence of each of them in the command line turns on an appropriate option. See \f[B]CONFIGURATION FILES\f[] section for details. .PP \f[C]\-r,\ \-\-remove\ \f[] .PP Remove a pool described by given pool set file descriptor. It is interpreted as a path to the pool set file relative to the pool set directory. .PP \f[C]\-f,\ \-\-force\f[] .PP Ignore errors when removing a pool file using \f[B]\[en]remove\f[] option. .SH CONFIGURATION FILES .PP The \f[B]rpmemd\f[] searches for the configuration files with following priorities: .IP \[bu] 2 The global configuration file located in \f[B]/etc/rpmemd/rpmemd.conf\f[]. .IP \[bu] 2 The user configuration file located in the user home directory (\f[B]$HOME/.rpmemd.conf\f[]). .PP The \f[B]rpmemd\f[] can also read configuration from the custom configuration file provided using \f[B]\[en]config\f[] command line option. See \f[B]OPTIONS\f[] section for details. .PP The default configuration is described in the \f[B]DEFAULT CONFIGURATION\f[] section. .PP The configuration file is a plain text file. Each line of the configuration file can store only one configuration option defined as a \f[I]key=value\f[] pair. Empty lines and lines starting with \f[I]#\f[] are omitted. .PP The allowed options are: .IP \[bu] 2 \f[C]log\-file\ =\ \f[] \- log file location .IP \[bu] 2 \f[C]poolset\-dir\ =\ \f[] \- pool set files directory .IP \[bu] 2 \f[C]persist\-apm\ =\ {yes|no}\f[] \- enable \f[B]The Appliance Persistency Method\f[]. This option must be set only if the target platform has non\-allocating writes IO enabled. See \f[B]PERSISTENCY METHODS\f[] section for details. .IP \[bu] 2 \f[C]persist\-general\ =\ {yes|no}\f[] \- enable \f[B]The General Purpose Server Persistency Method\f[]. See \f[B]PERSISTENCY METHODS\f[] section for details. .IP \[bu] 2 \f[C]use\-syslog\ =\ {yes|no}\f[] \- use \f[B]syslog\f[](3) for logging messages instead of log file .IP \[bu] 2 \f[C]log\-level\ =\ \f[] \- set log level value. Accepted \f[I]\f[] values are: .RS 2 .IP \[bu] 2 \f[B]err\f[] \- error conditions .IP \[bu] 2 \f[B]warn\f[] \- warning conditions .IP \[bu] 2 \f[B]notice\f[] \- normal, but significant conditions .IP \[bu] 2 \f[B]info\f[] \- informational message .IP \[bu] 2 \f[B]debug\f[] \- debug\-level message .RE .PP The \f[B]$HOME\f[] sub\-string in the \f[I]poolset\-dir\f[] path is replaced with the current user home directory. .SH EXAMPLE .PP Example of the configuration file: .IP .nf \f[C] #\ This\ is\ an\ example\ of\ configuration\ file log\-file\ =\ $HOME/.logs/rpmemd.log poolset\-dir\ =\ $HOME/poolsets/ persist\-apm\ =\ yes persist\-general\ =\ no use\-syslog\ =\ no\ #\ Use\ log\ file\ instead\ of\ syslog log\-level\ =\ info \f[] .fi .SH DEFAULT CONFIGURATION .PP The \f[B]rpmemd\f[] default configuration is equivalent of the following configuration file: .IP .nf \f[C] log\-file\ =\ /var/log/rpmemd.log poolset\-dir\ =\ $HOME persist\-apm\ =\ no persist\-general\ =\ yes use\-syslog\ =\ yes log\-level\ =\ err \f[] .fi .SH PERSISTENCY METHODS .PP The \f[B]librpmem\f[](7) supports two methods for making data written to remote persistent memory durable. The difference between the use of the two mechanisms is based on whether \f[B]librpmem\f[](7) will make use of non\-allocating writes on the remote node. .IP \[bu] 2 \f[B]The General Purpose Server Persistency Method\f[] does not have any requirements for the platform on which the target daemon runs and can be enabled by administrator using the \f[I]persist\-general\f[] option. This method utilize \f[B]libpmem\f[](7) persistency mechanisms on remote node and requires additional communication between initiator and remote node using the in\-band connection. .IP \[bu] 2 \f[B]The Appliance Persistency Method\f[] requires non\-allocating writes enabled on the platform and can be enabled by administrator using \f[I]persist\-apm\f[] option. This method requires to issue an RDMA READ operation after the RDMA WRITE operations performed on requested chunk of memory. .PP \[lq]Non\-allocating write requests\[rq] is the Intel Integrated IO Controller mode where all incoming PCIe writes will utilize non\-allocating buffers for the write requests. Non\-allocating writes are guaranteed to bypass all of the CPU caches and force the write requests to flow directly to the Integrated Memory Controller without delay. .PP The \f[B]rpmemd\f[] dynamically choose the appropriate persistency method and the flushing to persistence primitive for GPSPM for each opened pool set name depending on available persistency methods and whether all pool set parts are stored in the persistent memory. .PP If the \f[B]Appliance Persistency Method\f[] is enabled and the pool set is stored in the persistent memory \f[B]rpmemd\f[] will use the \f[B]Appliance Persistency Method\f[]. If the pool set is NOT stored in the persistent memory it will fallback to the \f[B]General Puropose Server Persistency Method\f[] with \f[B]pmem_msync\f[](3). .PP If the \f[B]General Puropose Server Persistency Method\f[] is enabled and the pool set is stored in the persistent memory \f[B]rpmemd\f[] will use \f[B]pmem_persist\f[](3). If the pool set is NOT stored in the persistent momory it will use \f[B]pmem_msync\f[](3). .PP See \f[B]pmem_persist\f[](3) and \f[B]pmem_msync\f[](3) for more details. .SH SEE ALSO .PP \f[B]ssh\f[](1), \f[B]pmem_msync\f[](3), \f[B]pmem_persist\f[](3), \f[B]syslog\f[](3), \f[B]libpmem\f[](7), \f[B]libpmemobj\f[](7), \f[B]librpmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/toid.3000066400000000000000000000000231331545616200161770ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_assign.3000066400000000000000000000000231331545616200175430ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_declare.3000066400000000000000000000127151331545616200176710ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "TOID_DECLARE" "3" "2018-05-21" "PMDK - pmemobj API version 2.3" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]TOID_DECLARE\f[](), \f[B]TOID_DECLARE_ROOT\f[](), \f[B]TOID\f[](), \f[B]TOID_TYPE_NUM\f[](), \f[B]TOID_TYPE_NUM_OF\f[](), \f[B]TOID_VALID\f[](), \f[B]OID_INSTANCEOF\f[](), \f[B]TOID_ASSIGN\f[](), \f[B]TOID_IS_NULL\f[](), \f[B]TOID_EQUALS\f[](), \f[B]TOID_TYPEOF\f[](), \f[B]TOID_OFFSETOF\f[](), \f[B]DIRECT_RW\f[](), \f[B]D_RW\f[](), \f[B]DIRECT_RO\f[](), \f[B]D_RO\f[]() \[en] libpmemobj type safety mechanism .SH SYNOPSIS .IP .nf \f[C] #include\ TOID_DECLARE(TYPE,\ uint64_t\ type_num) TOID_DECLARE_ROOT(ROOT_TYPE) TOID(TYPE) TOID_TYPE_NUM(TYPE) TOID_TYPE_NUM_OF(TOID\ oid) TOID_VALID(TOID\ oid) OID_INSTANCEOF(PMEMoid\ oid,\ TYPE) TOID_ASSIGN(TOID\ o,\ VALUE) TOID_IS_NULL(TOID\ o) TOID_EQUALS(TOID\ lhs,\ TOID\ rhs) TOID_TYPEOF(TOID\ o) TOID_OFFSETOF(TOID\ o,\ FILED) DIRECT_RW(TOID\ oid) D_RW(TOID\ oid) DIRECT_RO(TOID\ oid) D_RO(TOID\ oid) \f[] .fi .SH DESCRIPTION .PP Operating on untyped object handles, as well as on direct untyped object pointers (\f[I]void*\f[]), may be confusing and error\-prone. To facilitate type safety, \f[B]libpmemobj\f[](7) defines a set of macros that provide static type enforcement, catching potential errors at compile time. For example, a compile\-time error is generated when an attempt is made to assign a handle to an object of one type to the object handle variable of another type of object. .PP The \f[B]TOID_DECLARE\f[]() macro declares a typed \f[I]OID\f[] of user\-defined type \f[I]TYPE\f[] and type number \f[I]type_num\f[]. .PP The \f[B]TOID_DECLARE_ROOT\f[]() macro declares a typed \f[I]OID\f[] of user\-defined type \f[I]ROOT_TYPE\f[] and root object type number \f[B]POBJ_ROOT_TYPE_NUM\f[]. .PP The \f[B]TOID\f[]() macro declares a handle to an object of type \f[I]TYPE\f[], where \f[I]TYPE\f[] is the name of a user\-defined structure. The typed \f[I]OID\f[] must be declared first using the \f[B]TOID_DECLARE\f[](), \f[B]TOID_DECLARE_ROOT\f[](), \f[B]POBJ_LAYOUT_TOID\f[](3) or \f[B]POBJ_LAYOUT_ROOT\f[](3) macros. .PP The \f[B]TOID_TYPE_NUM\f[]() macro returns the type number of the type specified by \f[I]TYPE\f[]. .PP The \f[B]TOID_TYPE_NUM_OF\f[]() macro returns the type number of the object specified by \f[I]oid\f[]. The type number is read from the typed \f[I]OID\f[]. .PP The \f[B]TOID_VALID\f[]() macro validates whether the type number stored in the object's metadata is equal to the type number read from the typed \f[I]OID\f[]. .PP The \f[B]OID_INSTANCEOF\f[]() macro checks whether the \f[I]oid\f[] is of type \f[I]TYPE\f[]. .PP The \f[B]TOID_ASSIGN\f[]() macro assigns the object handle \f[I]VALUE\f[] to typed \f[I]OID\f[] \f[I]o\f[]. .PP The \f[B]TOID_IS_NULL\f[]() macro evaluates to true if the object handle represented by \f[I]o\f[] is \f[B]OID_NULL\f[]. .PP The \f[B]TOID_EQUALS\f[]() macro evaluates to true if both the \f[I]lhs\f[] and \f[I]rhs\f[] object handles reference the same persistent object. .PP The \f[B]TOID_TYPEOF\f[]() macro returns the type of the object handle represented by typed \f[I]OID\f[] \f[I]o\f[]. .PP The \f[B]TOID_OFFSETOF\f[]() macro returns the offset of the \f[I]FIELD\f[] member from the start of the object represented by \f[I]o\f[]. .PP The \f[B]DIRECT_RW\f[]() macro and its shortened form \f[B]D_RW\f[]() return a typed write pointer (\f[I]TYPE*\f[]) to an object represented by \f[I]oid\f[]. If \f[I]oid\f[] is \f[B]OID_NULL\f[], the macro evaluates to NULL. .PP The \f[B]DIRECT_RO\f[]() macro and its shortened form \f[B]D_RO\f[]() return a typed read\-only (const) pointer (\f[I]TYPE*\f[]) to an object represented by \f[I]oid\f[]. If \f[I]oid\f[] is \f[B]OID_NULL\f[], the macro evaluates to NULL. .SH SEE ALSO .PP \f[B]OID_IS_NULL\f[](3), \f[B]POBJ_LAYOUT_ROOT\f[](3), \f[B]POBJ_LAYOUT_TOID\f[](3), \f[B]libpmemobj\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/toid_declare_root.3000066400000000000000000000000231331545616200207210ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_equals.3000066400000000000000000000000231331545616200175510ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_is_null.3000066400000000000000000000000231331545616200177240ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_offsetof.3000066400000000000000000000000231331545616200200720ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_type_num.3000066400000000000000000000000231331545616200201170ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_type_num_of.3000066400000000000000000000000231331545616200206030ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_typeof.3000066400000000000000000000000231331545616200175650ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/toid_valid.3000066400000000000000000000000231331545616200173560ustar00rootroot00000000000000.so toid_declare.3 pmdk-1.4.1/doc/generated/tx_add.3000066400000000000000000000000331331545616200165040ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_add_direct.3000066400000000000000000000000331331545616200200360ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_add_field.3000066400000000000000000000000331331545616200176470ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_add_field_direct.3000066400000000000000000000000331331545616200212010ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_alloc.3000066400000000000000000000000271331545616200170510ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_begin.3000066400000000000000000000000271331545616200170430ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_begin_cb.3000066400000000000000000000000271331545616200175070ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_begin_param.3000066400000000000000000000000271331545616200202230ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_end.3000066400000000000000000000000271331545616200165250ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_finally.3000066400000000000000000000000271331545616200174150ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_free.3000066400000000000000000000000271331545616200167000ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_memcpy.3000066400000000000000000000000331331545616200172460ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_memset.3000066400000000000000000000000331331545616200172460ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_new.3000066400000000000000000000000271331545616200165500ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_onabort.3000066400000000000000000000000271331545616200174230ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_oncommit.3000066400000000000000000000000271331545616200176040ustar00rootroot00000000000000.so pmemobj_tx_begin.3 pmdk-1.4.1/doc/generated/tx_realloc.3000066400000000000000000000000271331545616200174000ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_set.3000066400000000000000000000000331331545616200165470ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_set_direct.3000066400000000000000000000000331331545616200201010ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_strdup.3000066400000000000000000000000271331545616200173000ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_wcsdup.3000066400000000000000000000000271331545616200172640ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_xadd.3000066400000000000000000000000331331545616200166740ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_xadd_direct.3000066400000000000000000000000331331545616200202260ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_xadd_field.3000066400000000000000000000000331331545616200200370ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_xadd_field_direct.3000066400000000000000000000000331331545616200213710ustar00rootroot00000000000000.so pmemobj_tx_add_range.3 pmdk-1.4.1/doc/generated/tx_xalloc.3000066400000000000000000000000271331545616200172410ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_zalloc.3000066400000000000000000000000271331545616200172430ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_znew.3000066400000000000000000000000271331545616200167420ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/tx_zrealloc.3000066400000000000000000000000271331545616200175720ustar00rootroot00000000000000.so pmemobj_tx_alloc.3 pmdk-1.4.1/doc/generated/vmem_aligned_alloc.3000066400000000000000000000000221331545616200210400ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/generated/vmem_calloc.3000066400000000000000000000000221331545616200175200ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/generated/vmem_check.3000066400000000000000000000000221331545616200173400ustar00rootroot00000000000000.so vmem_create.3 pmdk-1.4.1/doc/generated/vmem_check_version.3000066400000000000000000000000231331545616200211060ustar00rootroot00000000000000.so man7/libvmem.7 pmdk-1.4.1/doc/generated/vmem_create.3000066400000000000000000000172331331545616200175420ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "VMEM_CREATE" "3" "2018-05-21" "PMDK - vmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]vmem_create\f[](), \f[B]vmem_create_in_region\f[](), \f[B]vmem_delete\f[](), \f[B]vmem_check\f[](), \f[B]vmem_stats_print\f[]() \[en] volatile memory pool management .SH SYNOPSIS .IP .nf \f[C] #include\ VMEM\ *vmem_create(const\ char\ *dir,\ size_t\ size); VMEM\ *vmem_create_in_region(void\ *addr,\ size_t\ size); void\ vmem_delete(VMEM\ *vmp); int\ vmem_check(VMEM\ *vmp); void\ vmem_stats_print(VMEM\ *vmp,\ const\ char\ *opts); \f[] .fi .SH DESCRIPTION .PP To use \f[B]libvmem\f[], a \f[I]memory pool\f[] is first created. This is most commonly done with the \f[B]vmem_create\f[]() function described below. The other \f[B]libvmem\f[] functions are for less common cases, where applications have special needs for creating pools or examining library state. .PP The \f[B]vmem_create\f[]() function creates a memory pool and returns an opaque memory pool handle of type \f[I]VMEM*\f[]. The handle is then used with \f[B]libvmem\f[] functions such as \f[B]vmem_malloc\f[]() and \f[B]vmem_free\f[]() to provide the familiar \f[I]malloc\f[]\-like programming model for the memory pool. .PP The pool is created by allocating a temporary file in the directory \f[I]dir\f[], in a fashion similar to \f[B]tmpfile\f[](3), so that the file name does not appear when the directory is listed, and the space is automatically freed when the program terminates. \f[I]size\f[] bytes are allocated and the resulting space is memory\-mapped. The minimum \f[I]size\f[] value allowed by the library is defined in \f[B]\f[] as \f[B]VMEM_MIN_POOL\f[]. The maximum allowed size is not limited by \f[B]libvmem\f[], but by the file system on which \f[I]dir\f[] resides. The \f[I]size\f[] passed in is the raw size of the memory pool. \f[B]libvmem\f[] will use some of that space for its own metadata, so the usable space will be less. .PP \f[B]vmem_create\f[]() can also be called with the \f[B]dir\f[] argument pointing to a device DAX. In that case the entire device will serve as a volatile pool. Device DAX is the device\-centric analogue of Filesystem DAX. It allows memory ranges to be allocated and mapped without need of an intervening file system. For more information please see \f[B]ndctl\-create\-namespace\f[](1). .PP \f[B]vmem_create_in_region\f[]() is an alternate \f[B]libvmem\f[] entry point for creating a memory pool. It is for the rare case where an application needs to create a memory pool from an already memory\-mapped region. Instead of allocating space from a file system, \f[B]vmem_create_in_region\f[]() is given the memory region explicitly via the \f[I]addr\f[] and \f[I]size\f[] arguments. Any data in the region is lost by calling \f[B]vmem_create_in_region\f[](), which will immediately store its own data structures for managing the pool there. As with \f[B]vmem_create\f[](), the minimum \f[I]size\f[] allowed is defined as \f[B]VMEM_MIN_POOL\f[]. The \f[I]addr\f[] argument must be page aligned. Undefined behavior occurs if \f[I]addr\f[] does not point to a contiguous memory region in the virtual address space of the calling process, or if the \f[I]size\f[] is larger than the actual size of the memory region pointed to by \f[I]addr\f[]. .PP The \f[B]vmem_delete\f[]() function releases the memory pool \f[I]vmp\f[]. If the memory pool was created using \f[B]vmem_create\f[](), deleting it allows the space to be reclaimed. .PP The \f[B]vmem_check\f[]() function performs an extensive consistency check of all \f[B]libvmem\f[] internal data structures in memory pool \f[I]vmp\f[]. Since an error return indicates memory pool corruption, applications should not continue to use a pool in this state. Additional details about errors found are logged when the log level is at least 1 (see \f[B]DEBUGGING AND ERROR HANDLING\f[] in \f[B]libvmem\f[](7)). During the consistency check performed by \f[B]vmem_check\f[](), other operations on the same memory pool are locked out. The checks are all read\-only; \f[B]vmem_check\f[]() never modifies the memory pool. This function is mostly useful for \f[B]libvmem\f[] developers during testing/debugging. .PP The \f[B]vmem_stats_print\f[]() function produces messages containing statistics about the given memory pool. Output is sent to \f[I]stderr\f[] unless the user sets the environment variable \f[B]VMEM_LOG_FILE\f[], or the application supplies a replacement \f[I]print_func\f[] (see \f[B]MANAGING LIBRARY BEHAVIOR\f[] in \f[B]libvmem\f[](7)). The \f[I]opts\f[] string can either be NULL or it can contain a list of options that change the statistics printed. General information that never changes during execution can be omitted by specifying \[lq]g\[rq] as a character within the opts string. The characters \[lq]m\[rq] and \[lq]a\[rq] can be specified to omit merged arena and per arena statistics, respectively; \[lq]b\[rq] and \[lq]l\[rq] can be specified to omit per size class statistics for bins and large objects, respectively. Unrecognized characters are silently ignored. Note that thread caching may prevent some statistics from being completely up to date. See \f[B]jemalloc\f[](3) for more detail (the description of the available \f[I]opts\f[] above was taken from that man page). .SH RETURN VALUE .PP On success, \f[B]vmem_create\f[]() returns an opaque memory pool handle of type \f[I]VMEM*\f[]. On error, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]vmem_create_in_region\f[]() returns an opaque memory pool handle of type \f[I]VMEM*\f[]. On error, it returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]vmem_delete\f[]() function returns no value. .PP The \f[B]vmem_check\f[]() function returns 1 if the memory pool is found to be consistent, and 0 if the check was performed but the memory pool is not consistent. If the check could not be performed, \f[B]vmem_check\f[]() returns \-1. .PP The \f[B]vmem_stats_print\f[]() function returns no value. .SH SEE ALSO .PP \f[B]ndctl\-create\-namespace\f[](1), \f[B]jemalloc\f[](3), \f[B]tmpfile\f[](3), \f[B]libvmem\f[](7) and \f[B]\f[] pmdk-1.4.1/doc/generated/vmem_create_in_region.3000066400000000000000000000000221331545616200215570ustar00rootroot00000000000000.so vmem_create.3 pmdk-1.4.1/doc/generated/vmem_delete.3000066400000000000000000000000221331545616200175250ustar00rootroot00000000000000.so vmem_create.3 pmdk-1.4.1/doc/generated/vmem_errormsg.3000066400000000000000000000000231331545616200201240ustar00rootroot00000000000000.so man7/libvmem.7 pmdk-1.4.1/doc/generated/vmem_free.3000066400000000000000000000000221331545616200172040ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/generated/vmem_malloc.3000066400000000000000000000203471331545616200175460ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.1.3 .\" .TH "VMEM_MALLOC" "3" "2018-05-21" "PMDK - vmem API version 1.1" "PMDK Programmer's Manual" .hy .\" Copyright 2014-2018, Intel Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" * Neither the name of the copyright holder nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH NAME .PP \f[B]vmem_malloc\f[](), \f[B]vmem_calloc\f[](), \f[B]vmem_realloc\f[](), \f[B]vmem_free\f[](), \f[B]vmem_aligned_alloc\f[](), \f[B]vmem_strdup\f[](), \f[B]vmem_wcsdup\f[](), \f[B]vmem_malloc_usable_size\f[]() \[en] memory allocation related functions .SH SYNOPSIS .IP .nf \f[C] #include\ void\ *vmem_malloc(VMEM\ *vmp,\ size_t\ size); void\ vmem_free(VMEM\ *vmp,\ void\ *ptr); void\ *vmem_calloc(VMEM\ *vmp,\ size_t\ nmemb,\ size_t\ size); void\ *vmem_realloc(VMEM\ *vmp,\ void\ *ptr,\ size_t\ size); void\ *vmem_aligned_alloc(VMEM\ *vmp,\ size_t\ alignment,\ size_t\ size); char\ *vmem_strdup(VMEM\ *vmp,\ const\ char\ *s); wchar_t\ *vmem_wcsdup(VMEM\ *vmp,\ const\ wchar_t\ *s); size_t\ vmem_malloc_usable_size(VMEM\ *vmp,\ void\ *ptr); \f[] .fi .SH DESCRIPTION .PP This section describes the \f[I]malloc\f[]\-like API provided by \f[B]libvmem\f[](7). These functions provide the same semantics as their libc namesakes, but operate on the memory pools specified by their first arguments. .PP The \f[B]vmem_malloc\f[]() function provides the same semantics as \f[B]malloc\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. It allocates specified \f[I]size\f[] bytes. .PP The \f[B]vmem_free\f[]() function provides the same semantics as \f[B]free\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. It frees the memory space pointed to by \f[I]ptr\f[], which must have been returned by a previous call to \f[B]vmem_malloc\f[](), \f[B]vmem_calloc\f[]() or \f[B]vmem_realloc\f[]() for \f[I]the same pool of memory\f[]. If \f[I]ptr\f[] is NULL, no operation is performed. .PP The \f[B]vmem_calloc\f[]() function provides the same semantics as \f[B]calloc\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. It allocates memory for an array of \f[I]nmemb\f[] elements of \f[I]size\f[] bytes each. The memory is set to zero. .PP The \f[B]vmem_realloc\f[]() function provides the same semantics as \f[B]realloc\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. It changes the size of the memory block pointed to by \f[I]ptr\f[] to \f[I]size\f[] bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will \f[I]not\f[] be initialized. .PP Unless \f[I]ptr\f[] is NULL, it must have been returned by an earlier call to \f[B]vmem_malloc\f[](), \f[B]vmem_calloc\f[]() or \f[B]vmem_realloc\f[](). If \f[I]ptr\f[] is NULL, then the call is equivalent to \f[I]vmem_malloc(vmp, size)\f[], for all values of \f[I]size\f[]; if \f[I]size\f[] is equal to zero, and \f[I]ptr\f[] is not NULL, then the call is equivalent to \f[I]vmem_free(vmp, ptr)\f[]. .PP The \f[B]vmem_aligned_alloc\f[]() function provides the same semantics as \f[B]aligned_alloc\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. It allocates \f[I]size\f[] bytes from the memory pool. The memory address will be a multiple of \f[I]alignment\f[], which must be a power of two. .PP The \f[B]vmem_strdup\f[]() function provides the same semantics as \f[B]strdup\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. Memory for the new string is obtained with \f[B]vmem_malloc\f[](), on the given memory pool, and can be freed with \f[B]vmem_free\f[]() on the same memory pool. .PP The \f[B]vmem_wcsdup\f[]() function provides the same semantics as \f[B]wcsdup\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. Memory for the new string is obtained with \f[B]vmem_malloc\f[](), on the given memory pool, and can be freed with \f[B]vmem_free\f[]() on the same memory pool. .PP The \f[B]vmem_malloc_usable_size\f[]() function provides the same semantics as \f[B]malloc_usable_size\f[](3), but operates on the memory pool \f[I]vmp\f[] instead of the process heap supplied by the system. .SH RETURN VALUE .PP On success, \f[B]vmem_malloc\f[]() returns a pointer to the allocated memory. If \f[I]size\f[] is 0, then \f[B]vmem_malloc\f[]() returns either NULL, or a unique pointer value that can later be successfully passed to \f[B]vmem_free\f[](). If \f[B]vmem_malloc\f[]() is unable to satisfy the allocation request, it returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]vmem_free\f[]() function returns no value. Undefined behavior occurs if frees do not correspond to allocated memory from the same memory pool. .PP On success, \f[B]vmem_calloc\f[]() returns a pointer to the allocated memory. If \f[I]nmemb\f[] or \f[I]size\f[] is 0, then \f[B]vmem_calloc\f[]() returns either NULL, or a unique pointer value that can later be successfully passed to \f[B]vmem_free\f[](). If \f[B]vmem_calloc\f[]() is unable to satisfy the allocation request, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]vmem_realloc\f[]() returns a pointer to the allocted memory, which may be different from \f[I]ptr\f[]. If the area pointed to was moved, a \f[I]vmem_free(vmp, ptr)\f[] is done. If \f[B]vmem_realloc\f[]() is unable to satisfy the allocation request, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]vmem_aligned_alloc\f[]() returns a pointer to the allocated memory. If \f[B]vmem_aligned_alloc\f[]() is unable to satisfy the allocation request, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]vmem_strdup\f[]() returns a pointer to a new string which is a duplicate of the string \f[I]s\f[]. If \f[B]vmem_strdup\f[]() is unable to satisfy the allocation request, it returns NULL and sets \f[I]errno\f[] appropriately. .PP On success, \f[B]vmem_wcsdup\f[]() returns a pointer to a new wide character string which is a duplicate of the wide character string \f[I]s\f[]. If \f[B]vmem_wcsdup\f[]() is unable to satisfy the allocation request, it returns NULL and sets \f[I]errno\f[] appropriately. .PP The \f[B]vmem_malloc_usable_size\f[]() function returns the number of usable bytes in the block of allocated memory pointed to by \f[I]ptr\f[], a pointer to a block of memory allocated by \f[B]vmem_malloc\f[]() or a related function. If \f[I]ptr\f[] is NULL, 0 is returned. .SH SEE ALSO .PP \f[B]calloc\f[](3), \f[B]free\f[](3), \f[B]malloc\f[](3), \f[B]malloc_usable_size\f[](3), \f[B]realloc\f[](3), \f[B]strdup\f[](3), \f[B]wcsdup\f[](3) \f[B]libvmem(7)\f[] and \f[B]\f[] pmdk-1.4.1/doc/generated/vmem_malloc_usable_size.3000066400000000000000000000000221331545616200221170ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/generated/vmem_realloc.3000066400000000000000000000000221331545616200177040ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/generated/vmem_set_funcs.3000066400000000000000000000000231331545616200202550ustar00rootroot00000000000000.so man7/libvmem.7 pmdk-1.4.1/doc/generated/vmem_stats_print.3000066400000000000000000000000221331545616200206350ustar00rootroot00000000000000.so vmem_create.3 pmdk-1.4.1/doc/generated/vmem_strdup.3000066400000000000000000000000221331545616200176040ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/generated/vmem_wcsdup.3000066400000000000000000000000221331545616200175700ustar00rootroot00000000000000.so vmem_malloc.3 pmdk-1.4.1/doc/libpmem/000077500000000000000000000000001331545616200146505ustar00rootroot00000000000000pmdk-1.4.1/doc/libpmem/libpmem.7.md000066400000000000000000000354441331545616200167760ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBPMEM, 7) collection: libpmem header: PMDK date: pmem API version 1.1 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libpmem.7 -- man page for libpmem) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[CAVEATS](#caveats)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[ENVIRONMENT](#environment)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also) # NAME # **libpmem** -- persistent memory support library # SYNOPSIS # ```c #include cc ... -lpmem ``` _UNICODE() ##### Library API versioning: ##### ```c _UWFUNC(pmem_check_version, =q= unsigned major_required, unsigned minor_required=e=) ``` ##### Error handling: ##### ```c _UWFUNC(pmem_errormsg, void) ``` ##### Other library functions: ##### A description of other **libpmem** functions can be found on the following manual pages: + most commonly used functions: **pmem_is_pmem**(3) + partial flushing operations: **pmem_flush**(3) + copying to persistent memory: **pmem_memmove_persist**(3) # DESCRIPTION # **libpmem** provides low-level *persistent memory* (pmem) support for applications using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of *non-volatile memory DIMMs* (NVDIMMs) provide this type of byte addressable access to storage. A *persistent memory aware file system* is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in the load/store, non-paged access to pmem. This library is for applications that use persistent memory directly, without the help of any library-supplied transactions or memory allocation. Higher-level libraries that build on **libpmem** are available and are recommended for most applications, see: + **libpmemobj**(7), a general use persistent memory API, providing memory allocation and transactional operations on variable-sized objects. + **libpmemblk**(7), providing pmem-resident arrays of fixed-sized blocks with atomic updates. + **libpmemlog**(7), providing a pmem-resident log file. Under normal usage, **libpmem** will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under **DEBUGGING AND ERROR HANDLING** below. # CAVEATS # **libpmem** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The _UW(pmem_check_version) function is used to determine whether the installed **libpmem** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = _U(pmem_check_version)(PMEM_MAJOR_VERSION, PMEM_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. When the version check performed by _UW(pmem_check_version) is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by _UW(pmem_check_version) must not be modified or freed. # ENVIRONMENT # **libpmem** can change its default behavior based on the following environment variables. These are largely intended for testing and are not normally required. + **PMEM_IS_PMEM_FORCE**=*val* If *val* is 0 (zero), then **pmem_is_pmem**(3) will always return false. Setting *val* to 1 causes **pmem_is_pmem**(3) to always return true. This variable is mostly used for testing but can be used to force pmem behavior on a system where a range of pmem is not detectable as pmem for some reason. >NOTE: Unlike the other variables, the value of **PMEM_IS_PMEM_FORCE** is not queried (and cached) at library initialization time, but on the first call to **pmem_is_pmem**(3). This means that in case of **libpmemlog**(7), **libpmemblk**(7), and **libpmemobj**(7), **PMEM_IS_PMEM_FORCE** may still be set or modified by the program until the first attempt to create or open the persistent memory pool. + **PMEM_NO_CLWB**=1 Setting this environment variable to 1 forces **libpmem** to never issue the **CLWB** instruction on Intel hardware, falling back to other cache flush instructions instead (**CLFLUSHOPT** or **CLFLUSH** on Intel hardware). Without this environment variable, **libpmem** will always use the **CLWB** instruction for flushing processor caches on platforms that support the instruction. This variable is intended for use during library testing but may be required for some rare cases where using **CLWB** has a negative impact on performance. + **PMEM_NO_CLFLUSHOPT**=1 Setting this environment variable to 1 forces **libpmem** to never issue the **CLFLUSHOPT** instruction on Intel hardware, falling back to the **CLFLUSH** instructions instead. Without this environment variable, **libpmem** will always use the **CLFLUSHOPT** instruction for flushing processor caches on platforms that support the instruction, but where **CLWB** is not available. This variable is intended for use during library testing. + **PMEM_NO_FLUSH**=1 Setting this environment variable to 1 forces most **libpmem** functions to never issue any of **CLFLUSH**, **CLFLUSHOPT** or **CLWB** instructions on Intel hardware. The only exceptions are **pmem_deep_flush**(3) and **pmem_deep_persist**(3) functions. + **PMEM_NO_FLUSH**=0 Setting this environment variable to 0 forces to always flush CPU caches using one of **CLFLUSH**, **CLFLUSHOPT** or **CLWB** instructions even if **pmem_has_auto_flush**(3) function returns true and the platform supports flushing the processor caches on power loss or system crash. + **PMEM_NO_MOVNT**=1 Setting this environment variable to 1 forces **libpmem** to never use the *non-temporal* move instructions on Intel hardware. Without this environment variable, **libpmem** will use the non-temporal instructions for copying larger ranges to persistent memory on platforms that support the instructions. This variable is intended for use during library testing. + **PMEM_MOVNT_THRESHOLD**=*val* This environment variable allows overriding the minimum length of the **pmem_memmove_persist**(3) operations, for which **libpmem** uses *non-temporal* move instructions. Setting this environment variable to 0 forces **libpmem** to always use the *non-temporal* move instructions if available. It has no effect if **PMEM_NO_MOVNT** is set to 1. This variable is intended for use during library testing. + **PMEM_MMAP_HINT**=*val* This environment variable allows overriding the hint address used by _UW(pmem_map_file). If set, it also disables mapping address randomization. This variable is intended for use during library testing and debugging. Setting it to some fairly large value (i.e. 0x10000000000) will very likely result in mapping the file at the specified address (if not used) or at the first unused region above given address, without adding any random offset. When debugging, this makes it easier to calculate the actual address of the persistent memory block, based on its offset in the file. In case of **libpmemobj** it simplifies conversion of a persistent object identifier (OID) into a direct pointer to the object. >NOTE: **Setting this environment variable affects all the PMDK libraries,** disabling mapping address randomization and causing the specified address to be used as a hint about where to place the mapping. # DEBUGGING AND ERROR HANDLING # If an error is detected during the call to a **libpmem** function, the application may retrieve an error message describing the reason for the failure from _UW(pmem_errormsg). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libpmem** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libpmem** are typically available on a development system. The normal version, accessed when a program is linked using the **-lpmem** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version of **libpmem**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the environment variable **LD_LIBRARY_PATH** to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **PMEM_LOG_LEVEL** The value of **PMEM_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **PMEM_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. The same information may be retrieved using _UW(pmem_errormsg). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **libpmem** developers. Unless **PMEM_LOG_FILE** is set, debugging output is written to *stderr*. + **PMEM_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **PMEM_LOG_FILE** is not set, output is written to *stderr*. # EXAMPLE # The following example uses **libpmem** to flush changes made to raw, memory-mapped persistent memory. >WARNING: There is nothing transactional about the **pmem_persist**(3) or **pmem_msync**(3) calls in this example. Interrupting the program may result in a partial write to pmem. Use a transactional library such as **libpmemobj**(7) to avoid torn updates. ```c #include #include #include #include #include #include #include #include #include /* using 4k of pmem for this example */ #define PMEM_LEN 4096 #define PATH "/pmem-fs/myfile" int main(int argc, char *argv[]) { char *pmemaddr; size_t mapped_len; int is_pmem; /* create a pmem file and memory map it */ if ((pmemaddr = _U(pmem_map_file)(PATH, PMEM_LEN, PMEM_FILE_CREATE, 0666, &mapped_len, &is_pmem)) == NULL) { perror("_U(pmem_map_file)"); exit(1); } /* store a string to the persistent memory */ strcpy(pmemaddr, "hello, persistent memory"); /* flush above strcpy to persistence */ if (is_pmem) pmem_persist(pmemaddr, mapped_len); else pmem_msync(pmemaddr, mapped_len); /* * Delete the mappings. The region is also * automatically unmapped when the process is * terminated. */ pmem_unmap(pmemaddr, mapped_len); } ``` See for more examples using the **libpmem** API. # ACKNOWLEDGEMENTS # **libpmem** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **dlclose**(3), **pmem_flush**(3), **pmem_is_pmem**(3), **pmem_memmove_persist**(3), **pmem_msync**(3), **pmem_persist**(3), **strerror**(3), **libpmemblk**(7), **libpmemcto**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmem/pmem_flush.3.md000066400000000000000000000216011331545616200174720ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEM_FLUSH, 3) collection: libpmem header: PMDK date: pmem API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmem_flush.3 -- man page for partial flushing operations [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmem_flush**(), **pmem_drain**(), **pmem_persist**(), **pmem_msync**(), **pmem_deep_flush**(), **pmem_deep_drain**(), **pmem_deep_persist**(), **pmem_has_hw_drain**(), **pmem_has_auto_flush**() -- check persistency, store persistent data and delete mappings # SYNOPSIS # ```c #include void pmem_persist(const void *addr, size_t len); int pmem_msync(const void *addr, size_t len); void pmem_flush(const void *addr, size_t len); void pmem_deep_flush(const void *addr, size_t len); (EXPERIMENTAL) int pmem_deep_drain(const void *addr, size_t len); (EXPERIMENTAL) int pmem_deep_persist(const void *addr, size_t len); (EXPERIMENTAL) void pmem_drain(void); int pmem_has_auto_flush(void); (EXPERIMENTAL) int pmem_has_hw_drain(void); ``` # DESCRIPTION # The functions in this section provide access to the stages of flushing to persistence, for the less common cases where an application needs more control of the flushing operations than the **pmem_persist**() function. >WARNING: Using **pmem_persist**() on a range where **pmem_is_pmem**(3) returns false may not do anything useful -- use **msync**(2) instead. The **pmem_persist**() function force any changes in the range \[*addr*, *addr*+*len*) to be stored durably in persistent memory. This is equivalent to calling **msync**(2) but may be more optimal and will avoid calling into the kernel if possible. There are no alignment restrictions on the range described by *addr* and *len*, but **pmem_persist**() may expand the range as necessary to meet platform alignment requirements. >WARNING: Like **msync**(2), there is nothing atomic or transactional about this call. Any unwritten stores in the given range will be written, but some stores may have already been written by virtue of normal cache eviction/replacement policies. Correctly written code must not depend on stores waiting until **pmem_persist**() is called to become persistent -- they can become persistent at any time before **pmem_persist**() is called. The **pmem_msync**() function is like **pmem_persist**() in that it forces any changes in the range \[*addr*, *addr*+*len*) to be stored durably. Since it calls **msync**(), this function works on either persistent memory or a memory mapped file on traditional storage. **pmem_msync**() takes steps to ensure the alignment of addresses and lengths passed to **msync**() meet the requirements of that system call. It calls **msync**() with the **MS_SYNC** flag as described in **msync**(2). Typically the application only checks for the existence of persistent memory once, and then uses that result throughout the program, for example: ```c /* do this call once, after the pmem is memory mapped */ int is_pmem = pmem_is_pmem(rangeaddr, rangelen); /* ... make changes to a range of pmem ... */ /* make the changes durable */ if (is_pmem) pmem_persist(subrangeaddr, subrangelen); else pmem_msync(subrangeaddr, subrangelen); /* ... */ ``` _WINUX(,=q= >WARNING: On Linux, **pmem_msync**() and **msync**(2) have no effect on memory ranges mapped from Device DAX. In case of memory ranges where **pmem_is_pmem**(3) returns true use **pmem_persist**() to force the changes to be stored durably in persistent memory. =e=) The **pmem_flush**() and **pmem_drain**() functions provide partial versions of the **pmem_persist**() function. **pmem_persist**() can be thought of as this: ```c void pmem_persist(const void *addr, size_t len) { /* flush the processor caches */ pmem_flush(addr, len); /* wait for any pmem stores to drain from HW buffers */ pmem_drain(); } ``` These functions allow advanced programs to create their own variations of **pmem_persist**(). For example, a program that needs to flush several discontiguous ranges can call **pmem_flush**() for each range and then follow up by calling **pmem_drain**() once. The semantics of **pmem_deep_flush**() function is the same as **pmem_flush**() function except that **pmem_deep_flush**() is indifferent to **PMEM_NO_FLUSH** environment variable (see **ENVIRONMENT** section in **libpmem**(7)) and always flushes processor caches. The behavior of **pmem_deep_persist**() function is the same as **pmem_persist**(), except that it provides higher reliability by flushing persistent memory stores to the most reliable persistence domain available to software rather than depending on automatic WPQ (write pending queue) flush on power failure (ADR). The **pmem_deep_flush**() and **pmem_deep_drain**() functions provide partial varsions of **pmem_deep_persist**() function. **pmem_deep_persist**() can be thought of as this: ``` int pmem_deep_persist(const void *addr, size_t len) { /* flush the processor caches */ pmem_deep_flush(addr, len); /* wait for any pmem stores to drain from HW buffers */ return pmem_deep_drain(addr, len); } ``` Since this operation is usually much more expensive than **pmem_persist**(), it should be used rarely. Typically the application should use this function only to flush the most critical data, which are required to recover after the power failure. The **pmem_has_auto_flush**() function checks if the machine supports automatic CPU cache flush on power failure or system crash. Function returns true only when each NVDIMM in the system is covered by this mechanism. The **pmem_has_hw_drain**() function checks if the machine supports an explicit *hardware drain* instruction for persistent memory. # RETURN VALUE # The **pmem_persist**() function returns no value. The **pmem_msync**() return value is the return value of **msync**(), which can return -1 and set *errno* to indicate an error. The **pmem_flush**(), **pmem_drain**() and **pmem_deep_flush**() functions return no value. The **pmem_deep_persist**() and **pmem_deep_drain**() return 0 on success. Otherwise it returns -1 and sets *errno* appropriately. If *len* is equal zero **pmem_deep_persist**() and **pmem_deep_drain**() return 0 but no flushing take place. The **pmem_has_auto_flush**() function returns 1 if given platform supports processor cache flushing on a power loss event. Otherwise it returns 0. On error it returns -1 and sets *errno* appropriately. The **pmem_has_hw_drain**() function returns true if the machine supports an explicit *hardware drain* instruction for persistent memory. On Intel processors with persistent memory, stores to persistent memory are considered persistent once they are flushed from the CPU caches, so this function always returns false. Despite that, programs using **pmem_flush**() to flush ranges of memory should still follow up by calling **pmem_drain**() once to ensure the flushes are complete. As mentioned above, **pmem_persist**() handles calling both **pmem_flush**() and **pmem_drain**(). # SEE ALSO # **msync**(2), **pmem_is_pmem**(3), **libpmem**(7) and **** pmdk-1.4.1/doc/libpmem/pmem_is_pmem.3.md000066400000000000000000000206501331545616200200050ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEM_IS_PMEM, 3) collection: libpmem header: PMDK date: pmem API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmem_is_pmem.3 -- man page for libpmem persistence and mapping functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[NOTES](#notes)
[CAVEATS](#caveats)
[BUGS](#bugs)
[SEE ALSO](#see-also)
# NAME # **pmem_is_pmem**(), _UW(pmem_map_file), **pmem_unmap**() -- check persistency, create and delete mappings # SYNOPSIS # ```c #include int pmem_is_pmem(const void *addr, size_t len); _UWFUNCR1(void, *pmem_map_file, *path, =q=size_t len, int flags, mode_t mode, size_t *mapped_lenp, int *is_pmemp=e=) int pmem_unmap(void *addr, size_t len); ``` _UNICODE() # DESCRIPTION # Most pmem-aware applications will take advantage of higher level libraries that alleviate the need for the application to call into **libpmem** directly. Application developers that wish to access raw memory mapped persistence directly (via **mmap**(2)) and that wish to take on the responsibility for flushing stores to persistence will find the functions described in this section to be the most commonly used. The **pmem_is_pmem**() function detects if the entire range \[*addr*, *addr*+*len*) consists of persistent memory. The implementation of **pmem_is_pmem**() requires a non-trivial amount of work to determine if the given range is entirely persistent memory. For this reason, it is better to call **pmem_is_pmem**() once when a range of memory is first encountered, save the result, and use the saved result to determine whether **pmem_persist**(3) or **msync**(2) is appropriate for flushing changes to persistence. Calling **pmem_is_pmem**() each time changes are flushed to persistence will not perform well. The _UW(pmem_map_file) function creates a new read/write mapping for a file. If **PMEM_FILE_CREATE** is not specified in *flags*, the entire existing file *path* is mapped, *len* must be zero, and *mode* is ignored. Otherwise, *path* is opened or created as specified by *flags* and *mode*, and *len* must be non-zero. _UW(pmem_map_file) maps the file using **mmap**(2), but it also takes extra steps to make large page mappings more likely. On success, _UW(pmem_map_file) returns a pointer to the mapped area. If *mapped_lenp* is not NULL, the length of the mapping is stored into \**mapped_lenp*. If *is_pmemp* is not NULL, a flag indicating whether the mapped file is actual pmem, or if **msync**() must be used to flush writes for the mapped range, is stored into \**is_pmemp*. The *flags* argument is 0 or the bitwise OR of one or more of the following file creation flags: + **PMEM_FILE_CREATE** - Create the file named *path* if it does not exist. *len* must be non-zero and specifies the size of the file to be created. If the file already exists, it will be extended or truncated to *len.* The new or existing file is then fully allocated to size *len* using **posix_fallocate**(3). *mode* specifies the mode to use in case a new file is created (see **creat**(2)). The remaining flags modify the behavior of _UW(pmem_map_file) when **PMEM_FILE_CREATE** is specified. + **PMEM_FILE_EXCL** - If specified in conjunction with **PMEM_FILE_CREATE**, and *path* already exists, then _UW(pmem_map_file) will fail with **EEXIST**. Otherwise, has the same meaning as **O_EXCL** on **open**(2), which is generally undefined. + **PMEM_FILE_SPARSE** - When specified in conjunction with **PMEM_FILE_CREATE**, create a sparse (holey) file using **ftruncate**(2) rather than allocating it using **posix_fallocate**(3). Otherwise ignored. + **PMEM_FILE_TMPFILE** - Create a mapping for an unnamed temporary file. Must be specified with **PMEM_FILE_CREATE**. *len* must be non-zero, *mode* is ignored (the temporary file is always created with mode 0600), and *path* must specify an existing directory name. If the underlying file system supports **O_TMPFILE**, the unnamed temporary file is created in the filesystem containing the directory *path*; if **PMEM_FILE_EXCL** is also specified, the temporary file may not subsequently be linked into the filesystem (see **open**(2)). Otherwise, the file is created in *path* and immediately unlinked. The *path* can point to a Device DAX. In this case only the **PMEM_FILE_CREATE** and **PMEM_FILE_SPARSE** flags are valid, but they are both ignored. For Device DAX mappings, *len* must be equal to either 0 or the exact size of the device. To delete mappings created with _UW(pmem_map_file), use **pmem_unmap**(). The **pmem_unmap**() function deletes all the mappings for the specified address range, and causes further references to addresses within the range to generate invalid memory references. It will use the address specified by the parameter *addr*, where *addr* must be a previously mapped region. **pmem_unmap**() will delete the mappings using **munmap**(2). # RETURN VALUE # The **pmem_is_pmem**() function returns true only if the entire range \[*addr*, *addr*+*len*) consists of persistent memory. A true return from **pmem_is_pmem**() means it is safe to use **pmem_persist**(3) and the related functions to make changes durable for that memory range. See also **CAVEATS**. On success, _UW(pmem_map_file) returns a pointer to the memory-mapped region and sets \**mapped_lenp* and \**is_pmemp* if they are not NULL. On error, it returns NULL, sets *errno* appropriately, and does not modify \**mapped_lenp* or \**is_pmemp*. On success, **pmem_unmap**() returns 0. On error, it returns -1 and sets *errno* appropriately. # NOTES # On Linux, **pmem_is_pmem**() returns true only if the entire range is mapped directly from Device DAX (/dev/daxX.Y) without an intervening file system. In the future, as file systems become available that support flushing with **pmem_persist**(3), **pmem_is_pmem**() will return true as appropriate. # CAVEATS # The result of **pmem_is_pmem**() query is only valid for the mappings created using _UW(pmem_map_file). For other memory regions, in particular those created by a direct call to **mmap**(2), **pmem_is_pmem**() always returns false, even if the queried range is entirely persistent memory. Not all file systems support **posix_fallocate**(3). _UW(pmem_map_file) will fail if **PMEM_FILE_CREATE** is specified without **PMEM_FILE_SPARSE** and the underlying file system does not support **posix_fallocate**(3). # SEE ALSO # **creat**(2), **ftruncate**(2), **mmap**(2), **msync**(2), **munmap**(2), **open**(2), **pmem_persist**(3), **posix_fallocate**(3), **libpmem**(7) and **** pmdk-1.4.1/doc/libpmem/pmem_memmove_persist.3.md000066400000000000000000000130221331545616200215650ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEM_MEMMOVE_PERSIST, 3) collection: libpmem header: PMDK date: pmem API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmem_memmove_persist.3 -- man page for functions that provide optimized copying to persistent memory [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmem_memmove_persist**(), **pmem_memcpy_persist**(), **pmem_memset_persist**(), **pmem_memmove_nodrain**(), **pmem_memcpy_nodrain**(), **pmem_memset_nodrain**() -- functions that provide optimized copying to persistent memory # SYNOPSIS # ```c #include void *pmem_memmove_persist(void *pmemdest, const void *src, size_t len); void *pmem_memcpy_persist(void *pmemdest, const void *src, size_t len); void *pmem_memset_persist(void *pmemdest, int c, size_t len); void *pmem_memmove_nodrain(void *pmemdest, const void *src, size_t len); void *pmem_memcpy_nodrain(void *pmemdest, const void *src, size_t len); void *pmem_memset_nodrain(void *pmemdest, int c, size_t len); ``` # DESCRIPTION # The **pmem_memmove_persist**(), **pmem_memcpy_persist**(), and **pmem_memset_persist**(), functions provide the same memory copying as their namesakes **memmove**(3), **memcpy**(3) and **memset**(3), and ensure that the result has been flushed to persistence before returning. For example, the following code is functionally equivalent to **pmem_memmove_persist**(): ```c void * pmem_memmove_persist(void *pmemdest, const void *src, size_t len) { void *retval = memmove(pmemdest, src, len); pmem_persist(pmemdest, len); return retval; } ``` Calling **pmem_memmove_persist**() may out-perform the above code, however, since the **libpmem**(7) implementation may take advantage of the fact that *pmemdest* is persistent memory and use instructions such as *non-temporal* stores to avoid the need to flush processor caches. >WARNING: Using these functions where **pmem_is_pmem**(3) returns false may not do anything useful. Use the normal libc functions in that case. The **pmem_memmove_nodrain**(), **pmem_memcpy_nodrain**() and **pmem_memset_nodrain**() functions are similar to **pmem_memmove_persist**(), **pmem_memcpy_persist**(), and **pmem_memset_persist**() described above, except they skip the final **pmem_drain**() step. This allows applications to optimize cases where several ranges are being copied to persistent memory, followed by a single call to **pmem_drain**(). The following example illustrates how these functions might be used to avoid multiple calls to **pmem_drain**() when copying several ranges of memory to pmem: ```c /* ... write several ranges to pmem ... */ pmem_memcpy_nodrain(pmemdest1, src1, len1); pmem_memcpy_nodrain(pmemdest2, src2, len2); /* ... */ /* wait for any pmem stores to drain from HW buffers */ pmem_drain(); ``` # RETURN VALUE # The **pmem_memmove_persist**(), **pmem_memcpy_persist**(), **pmem_memset_persist**(), **pmem_memmove_nodrain**(), **pmem_memcpy_nodrain**() and **pmem_memset_nodrain**() functions return the address of the destination. # CAVEATS # After calling any of the *\_nodrain* functions (**pmem_memmove_nodrain**(), **pmem_memcpy_nodrain**() or **pmem_memset_nodrain**()) you should not expect memory to be visible to other threads before calling **pmem_drain**(3) or any of the *\_persist* functions. This is because those functions may use non-temporal store instructions, which are weakly ordered. See "Intel 64 and IA-32 Architectures Software Developer's Manual", Volume 1, "Caching of Temporal vs. Non-Temporal Data" section for details. # SEE ALSO # **memcpy**(3), **memmove**(3), **memset**(3), **libpmem**(7) and **** pmdk-1.4.1/doc/libpmemblk/000077500000000000000000000000001331545616200153415ustar00rootroot00000000000000pmdk-1.4.1/doc/libpmemblk/libpmemblk.7.md000066400000000000000000000313311331545616200201470ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBPMEMBLK, 7) collection: libpmemblk header: PMDK date: pmemblk API version 1.1 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libpmemblk.7 -- man page for libpmemblk) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[MANAGING LIBRARY BEHAVIOR](#managing-library-behavior-1)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[BUGS](#bugs)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also)
# NAME # **libpmemblk** -- persistent memory resident array of blocks # SYNOPSIS # ```c #include cc ... -lpmemblk -lpmem ``` _UNICODE() ##### Library API versioning: ##### ```c _UWFUNC(pmemblk_check_version, =q= unsigned major_required, unsigned minor_required=e=) ``` ##### Managing library behavior: ##### ```c void pmemblk_set_funcs( void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s)); ``` ##### Error handling: ##### ```c _UWFUNC(pmemblk_errormsg, void) ``` ##### Other library functions: ##### A description of other **libpmemblk** functions can be found on the following manual pages: **pmemblk_create**(3), **pmemblk_bsize**(3), **pmemblk_read**(3), **pmemblk_set_zero**(3) # DESCRIPTION # **libpmemblk** provides an array of blocks in *persistent memory* (pmem) such that updates to a single block are atomic. This library is intended for applications using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of *non-volatile memory DIMMs* (NVDIMMs) provide this type of byte addressable access to storage. A *persistent memory aware file system* is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in the load/store, non-paged access to pmem. **libpmemblk** builds on this type of memory mapped file. This library is for applications that need a potentially large array of blocks, all the same size, where any given block is updated atomically (the update cannot be *torn* by program interruption such as power failures). This library builds on the low-level pmem support provided by **libpmem**(3), handling the transactional update of the blocks, flushing to persistence, and recovery for the application. **libpmemblk** is one of a collection of persistent memory libraries available, the others are: + **libpmemobj**(7), a general use persistent memory API, providing memory allocation and transactional operations on variable-sized objects. + **libpmemlog**(7), providing a pmem-resident log file. + **libpmemcto**(7), providing close-to-open persistence. + **libpmem**(7), low-level persistent memory support. Under normal usage, **libpmemblk** will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under **DEBUGGING AND ERROR HANDLING** below. To use the atomic block arrays supplied by **libpmemblk**, a *memory pool* is first created using the _UW(pmemblk_create) function described in **pmemblk_create**(3). The other **libpmemblk** functions operate on the resulting block memory pool using the opaque handle, of type *PMEMblkpool\**, that is returned by _UW(pmemblk_create) or _UW(pmemblk_open). Internally, **libpmemblk** will use either **pmem_persist**(3) or **msync**(2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the **pmem_is_pmem**(3) function in **libpmem**(7) for more information). There is no need for applications to flush changes directly when using the block memory API provided by **libpmemblk**. # CAVEATS # **libpmemblk** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The _UW(pmemblk_check_version) function is used to determine whether the installed **libpmemblk** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = _U(pmemblk_check_version)(PMEMBLK_MAJOR_VERSION, PMEMBLK_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. When the version check performed by _UW(pmemblk_check_version) is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by _UW(pmemblk_check_version) must not be modified or freed. # MANAGING LIBRARY BEHAVIOR # The **pmemblk_set_funcs**() function allows an application to override memory allocation calls used internally by **libpmemblk**. Passing in NULL for any of the handlers will cause the **libpmemblk** default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4-8 kilobytes for each memory pool in use. # DEBUGGING AND ERROR HANDLING # The _UW(pmemblk_errormsg) function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code, as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libpmemblk** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libpmemblk** are typically available on a development system. The normal version, accessed when a program is linked using the **-lpmemblk** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. If an error is detected in a call to **libpmemblk**, the error message describing the failure may be retrieved with _UW(pmemblk_errormsg) as described above. A second version of **libpmemblk**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the **LD_LIBRARY_PATH** environment variable to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **PMEMBLK_LOG_LEVEL** The value of **PMEMBLK_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **PMEMBLK_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. The same information may be retrieved using _UW(pmemblk_errormsg). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **libpmemblk** developers. Unless **PMEMBLK_LOG_FILE** is set, debugging output is written to *stderr*. + **PMEMBLK_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **PMEMBLK_LOG_FILE** is not set, the logging output is written to *stderr*. See also **libpmem**(7) for information on other environment variables that may affect **libpmemblk** behavior. # EXAMPLE # The following example illustrates how the **libpmemblk** API is used. ```c #include #include #include #include #include #include /* size of the pmemblk pool -- 1 GB */ #define POOL_SIZE ((size_t)(1 << 30)) /* size of each element in the pmem pool */ #define ELEMENT_SIZE 1024 int main(int argc, char *argv[]) { const char path[] = "/pmem-fs/myfile"; PMEMblkpool *pbp; size_t nelements; char buf[ELEMENT_SIZE]; /* create the pmemblk pool or open it if it already exists */ pbp = _U(pmemblk_create)(path, ELEMENT_SIZE, POOL_SIZE, 0666); if (pbp == NULL) pbp = _U(pmemblk_open)(path, ELEMENT_SIZE); if (pbp == NULL) { perror(path); exit(1); } /* how many elements fit into the file? */ nelements = pmemblk_nblock(pbp); printf("file holds %zu elements", nelements); /* store a block at index 5 */ strcpy(buf, "hello, world"); if (pmemblk_write(pbp, buf, 5) < 0) { perror("pmemblk_write"); exit(1); } /* read the block at index 10 (reads as zeros initially) */ if (pmemblk_read(pbp, buf, 10) < 0) { perror("pmemblk_read"); exit(1); } /* zero out the block at index 5 */ if (pmemblk_set_zero(pbp, 5) < 0) { perror("pmemblk_set_zero"); exit(1); } /* ... */ pmemblk_close(pbp); } ``` See for more examples using the **libpmemblk** API. # BUGS # Unlike **libpmemobj**(7), data replication is not supported in **libpmemblk**. Thus, specifying replica sections in pool set files is not allowed. # ACKNOWLEDGEMENTS # **libpmemblk** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **msync**(2), **dlclose**(3), **pmemblk_bsize**(3), **pmemblk_create**(3), **pmemblk_read**(3), **pmemblk_set_zero**(3), **pmem_is_pmem**(3), **pmem_persist**(3), **strerror**(3), **libpmem**(7), **libpmemcto**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemblk/pmemblk_bsize.3.md000066400000000000000000000064761331545616200206640ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMBLK_BSIZE, 3) collection: libpmemblk header: PMDK date: pmemblk API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemblk_bsize.3 -- man page for functions that check number of available blocks or usable space in block memory pool) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemblk_bsize**(), **pmemblk_nblock**() -- check number of available blocks or usable space in block memory pool # SYNOPSIS # ```c #include size_t pmemblk_bsize(PMEMblkpool *pbp); size_t pmemblk_nblock(PMEMblkpool *pbp); ``` # DESCRIPTION # The **pmemblk_bsize**() function returns the block size of the specified block memory pool, that is, the value which was passed as *bsize* to _UW(pmemblk_create). *pbp* must be a block memory pool handle as returned by **pmemblk_open**(3) or **pmemblk_create**(3). The **pmemblk_nblock**() function returns the usable space in the block memory pool. *pbp* must be a block memory pool handle as returned by **pmemblk_open**(3) or **pmemblk_create**(3). # RETURN VALUE # The **pmemblk_bsize**() function returns the block size of the specified block memory pool. The **pmemblk_nblock**() function returns the usable space in the block memory pool, expressed as the number of blocks available. # SEE ALSO # **pmemblk_create**(3), **pmemblk_open**(3), **libpmemblk**(7) and **** pmdk-1.4.1/doc/libpmemblk/pmemblk_create.3.md000066400000000000000000000205151331545616200210010ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMBLK_CREATE, 3) collection: libpmemblk header: PMDK date: pmemblk API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemblk_create.3 -- man page for libpmemblk create, open, close and validate functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # _UW(pmemblk_create), _UW(pmemblk_open), **pmemblk_close**(), _UW(pmemblk_check) -- create, open, close and validate block pool # SYNOPSIS # ```c #include _UWFUNCR1(PMEMblkpool, *pmemblk_create, *path, =q=size_t bsize, size_t poolsize, mode_t mode=e=) _UWFUNCR1(PMEMblkpool, *pmemblk_open, *path, size_t bsize) void pmemblk_close(PMEMblkpool *pbp); _UWFUNCR1(int, pmemblk_check, *path, size_t bsize) ``` _UNICODE() # DESCRIPTION # The _UW(pmemblk_create) function creates a block memory pool with the given total *poolsize*, divided into as many elements of size *bsize* as will fit in the pool. Since the transactional nature of a block memory pool requires some space overhead in the memory pool, the resulting number of available blocks is less than *poolsize*/*bsize*, and is made available to the caller via the **pmemblk_nblock**(3) function. Given the specifics of the implementation, the number of available blocks for the user cannot be less than 256. This translates to at least 512 internal blocks. *path* specifies the name of the memory pool file to be created. *mode* specifies the permissions to use when creating the file, as described by **creat**(2). The memory pool file is fully allocated to the size *poolsize* using **posix_fallocate**(3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling _UW(pmemblk_create), and then specifying *poolsize* as zero. In this case _UW(pmemblk_create) will take the pool size from the size of the existing file, and will verify that the file appears to be empty by searching for any non-zero data in the pool header at the beginning of the file. The net pool size of a pool file is equal to the file size. The minimum net pool size allowed by the library for a block pool is defined in **\** as **PMEMBLK_MIN_POOL**. *bsize* can be any non-zero value; however, **libpmemblk** will silently round up the given size to **PMEMBLK_MIN_BLK**, as defined in **\**. Depending on the configuration of the system, the available non-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemblk memory pool could be limited by the capacity of a single memory device. **libpmemblk**(7) allows building a persistent memory resident array spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a *pool set* may be stored on a different memory device or pmem-aware filesystem. Creation of all the parts of the pool set can be done with _UW(pmemblk_create); however, the recommended method for creating pool sets is by using the **pmempool**(1) utility. When creating a pool set consisting of multiple files, the *path* argument passed to _UW(pmemblk_create) must point to the special *set* file that defines the pool layout and the location of all the parts of the pool set. The *poolsize* argument must be 0. The meaning of the *mode* argument does not change, except that the same *mode* is used for creation of all the parts of the pool set. For more information on pool set format, see **poolset**(5). The _UW(pmemblk_open) function opens an existing block memory pool. As with _UW(pmemblk_create), *path* must identify either an existing block memory pool file, or the *set* file used to create a pool set. The application must have permission to open the file and memory map the file or pool set with read/write permissions. If *bsize* is non-zero, _UW(pmemblk_open) will verify that the given block size matches the block size used when the pool was created. Otherwise, _UW(pmemblk_open) will open the pool without verifying the block size. The *bsize* can be determined using the **pmemblk_bsize**(3) function. The **pmemblk_close**() function closes the memory pool indicated by *pbp* and deletes the memory pool handle. The block memory pool itself lives on in the file that contains it and may be re-opened at a later time using _UW(pmemblk_open) as described above. The _UW(pmemblk_check) function performs a consistency check of the file indicated by *path*, and returns 1 if the memory pool is found to be consistent. If the pool is found not to be consistent, further use of the file with **libpmemblk** will result in undefined behavior. The debug version of **libpmemblk** will provide additional details on inconsistencies when **PMEMBLK_LOG_LEVEL** is at least 1, as described in the **DEBUGGING AND ERROR HANDLING** section in **libpmemblk**(7). _UW(pmemblk_check) opens the given *path* read-only so it never makes any changes to the file. This function is not supported on Device DAX. # RETURN VALUE # On success, _UW(pmemblk_create) returns a *PMEMblkpool\** handle to the block memory pool. On error, it returns NULL and sets *errno* appropriately. On success, _UW(pmemblk_open) returns a *PMEMblkpool\** handle that can be used with most of the functions in **libpmemblk**(7). On error, it returns NULL and sets *errno* appropriately. Possible errors include: + failure to open *path* + *path* specifies a *set* file and any of the pool set files cannot be opened + *path* specifies a *set* file and the actual size of any file does not match the corresponding part size defined in the *set* file + *bsize* is non-zero and does not match the block size given when the pool was created. *errno* is set to **EINVAL** in this case. The **pmemblk_close**() function returns no value. _UW(pmemblk_check) returns 1 if the memory pool is found to be consistent. If the check is successfully performed but the pool is found to be inconsistent, _UW(pmemblk_check) returns 0. This includes the case where *bsize* is non-zero and does not match the block size given when the pool was created. If the consistency check cannot be performed, _UW(pmemblk_check) returns -1 and sets *errno* appropriately. # CAVEATS # Not all file systems support **posix_fallocate**(3). _UW(pmemblk_create) will fail if the underlying file system does not support **posix_fallocate**(3). # SEE ALSO # **pmempool**(1), **creat**(2), **pmemblk_nblock**(3), **posix_fallocate**(3), **poolset**(5), **libpmemblk**(7) and **** pmdk-1.4.1/doc/libpmemblk/pmemblk_read.3.md000066400000000000000000000064421331545616200204540ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMBLK_READ, 3) collection: libpmemblk header: PMDK date: pmemblk API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemblk_read.3 -- man page for libpmemblk read and write functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemblk_read**(), **pmemblk_write**() -- read or write a block from a block memory pool # SYNOPSIS # ```c #include int pmemblk_read(PMEMblkpool *pbp, void *buf, long long blockno); int pmemblk_write(PMEMblkpool *pbp, const void *buf, long long blockno); ``` # DESCRIPTION # The **pmemblk_read**() function reads the block with block number *blockno* from memory pool *pbp* into the buffer *buf*. Reading a block that has never been written by **pmemblk_write**() will return a block of zeroes. The **pmemblk_write**() function writes a block from *buf* to block number *blockno* in the memory pool *pbp*. The write is atomic with respect to other reads and writes. In addition, the write cannot be torn by program failure or system crash; on recovery the block is guaranteed to contain either the old data or the new data, never a mixture of both. # RETURN VALUE # On success, the **pmemblk_read**() and **pmemblk_write**() functions return 0. On error, they return -1 and set *errno* appropriately. # SEE ALSO # **libpmemblk**(7) and **** pmdk-1.4.1/doc/libpmemblk/pmemblk_set_zero.3.md000066400000000000000000000063601331545616200213720ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMBLK_SET_ZERO, 3) collection: libpmemblk header: PMDK date: pmemblk API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemblk_set_zero.3 -- man page for block management functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemblk_set_zero**(), **pmemblk_set_error**() -- block management functions # SYNOPSIS # ```c #include int pmemblk_set_zero(PMEMblkpool *pbp, long long blockno); int pmemblk_set_error(PMEMblkpool *pbp, long long blockno); ``` # DESCRIPTION # The **pmemblk_set_zero**() function writes zeros to block number *blockno* in persistent memory resident array of blocks *pbp*. Using this function is faster than actually writing a block of zeros since **libpmemblk**(7) uses metadata to indicate the block should read back as zero. The **pmemblk_set_error**() function sets the error state for block number *blockno* in persistent memory resident array of blocks *pbp*. A block in the error state returns *errno* **EIO** when read. Writing the block clears the error state and returns the block to normal use. # RETURN VALUE # On success, **pmemblk_set_zero**() and **pmemblk_set_error**() return 0. On error, they return -1 and set *errno* appropriately. # SEE ALSO # **libpmemblk**(7) and **** pmdk-1.4.1/doc/libpmemcto/000077500000000000000000000000001331545616200153565ustar00rootroot00000000000000pmdk-1.4.1/doc/libpmemcto/libpmemcto.7.md000066400000000000000000000345261331545616200202120ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBPMEMCTO, 7) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libpmemcto.7 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[CAVEATS](#caveats)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[MANAGING LIBRARY BEHAVIOR](#managing-library-behavior-1)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[BUGS](#bugs)
[NOTES](#notes)
[AVAILABILITY](#availability)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also)
# NAME # **libpmemcto** -- close-to-open persistence (EXPERIMENTAL) # SYNOPSIS # ```c #include cc ... -lpmemcto -lpmem ``` _UNICODE() ##### Library API versioning: ##### ```c _UWFUNC(pmemcto_check_version, =q= unsigned major_required, unsigned minor_required=e=) ``` ##### Managing library behavior: ##### ```c void pmemcto_set_funcs( void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s), void (*print_func)(const char *s)); ``` ##### Error handling: ##### ```c _UWFUNC(pmemcto_errormsg, void) ``` ##### Other library functions: ##### A description of other **libpmemcto** functions can be found on the following manual pages: **pmemcto_aligned_alloc**(3), **pmemcto_malloc**(3), **pmemcto_malloc_usable_size**(3), **pmemcto_open**(3), **pmemcto_set_root_pointer**(3), **pmemcto_stats_print**(3), **pmemcto_strdup**(3), **pmemcto_wcsdup**(3) # DESCRIPTION # **libpmemcto** is a *persistent memory* allocator with no overhead imposed by run-time flushing or transactional updates: + It runs at traditional **volatile** memory allocator speeds - there is no flushing or consistency check at run-time. + An overhead imposed only when program exits normally and have to flush the file. + The program flushes the pool contents when it exits, and then rebuilds the pool on the next run. + If the program crashes before flushing the file (or if flushing fails), the pool is in an inconsistent state causing subsequent pool opening to fail. **libpmemcto** provides common *malloc-like* interfaces to persistent memory pools built on memory-mapped files. **libpmemcto** uses the **mmap**(2) system call to create a pool of persistent memory. The library is intended for applications using *Direct Access* storage (DAX), which is memory-addressable persistent storage that supports load/store access without being paged via the system page cache. A Persistent Memory-aware file system is typically used to provide this type of access. Memory-mapping a file from a Persistent Memory-aware file system provides the raw memory pools, and this library supplies the more familiar *malloc-like* interfaces on top of those pools. **libpmemcto** is one of a collection of persistent memory libraries available, the others are: + **libpmemobj**(7), a general use persistent memory API, providing memory allocation and transactional operations on variable-sized objects. + **libpmemblk**(7), providing pmem-resident arrays of fixed-sized blocks with atomic updates. + **libpmemlog**(7), providing a pmem-resident log file. + **libpmem**(7), low-level persistent memory support. Under normal usage, **libpmemcto** will never print messages or intentionally cause the process to exit. Exceptions to this are prints caused by calls to **pmemcto_stats_print**(3), or by enabling debugging as described under **DEBUGGING AND ERROR HANDLING** below. The library uses **pthreads**(7) to be fully MT-safe, but never creates or destroys threads itself. The library does not make use of any signals, networking, and never calls **select**() or **poll**(). The system memory allocation routines like **malloc**() and **free**() are used by **libpmemcto** for managing a small amount of run-time state, but applications are allowed to override these calls if necessary (see **pmemcto_set_funcs**()). This library builds on the low-level pmem support provided by **libpmem**(7). To use close-to-open persistence supplied by **libpmemcto**, a *memory pool* is first created using the _UW(pmemcto_create) function described in **pmemcto_open**(3). The other **libpmemcto** functions operate on the resulting block memory pool using the opaque handle, of type *PMEMctopool\**, that is returned by _UW(pmemcto_create) or _UW(pmemcto_open). Internally, **libpmemcto** will use either **pmem_persist**(3) or **msync**(2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the **pmem_is_pmem**(3) function in **libpmem**(7) for more information). There is no need for applications to flush changes directly when using the close-to-open persistence memory API provided by **libpmemcto**. # CAVEATS # **libpmemcto** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The _UW(pmemcto_check_version) function is used to determine whether the installed **libpmemcto** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = _U(pmemcto_check_version)(PMEMCTO_MAJOR_VERSION, PMEMCTO_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. When the version check performed by _UW(pmemcto_check_version) is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by _UW(pmemcto_check_version) must not be modified or freed. # MANAGING LIBRARY BEHAVIOR # The **pmemcto_set_funcs**() function allows an application to override memory allocation calls used internally by **libpmemcto**. Passing in NULL for any of the handlers will cause the **libpmemcto** default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4-8 kilobytes for each memory pool in use. # DEBUGGING AND ERROR HANDLING # The _UW(pmemcto_errormsg) function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code, as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libpmemcto** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libpmemcto** are typically available on a development system. The normal version, accessed when a program is linked using the **-lpmemcto** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. If an error is detected in a call to **libpmemcto**, the error message describing the failure may be retrieved with _UW(pmemcto_errormsg) as described above. A second version of **libpmemcto**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the **LD_LIBRARY_PATH** environment variable to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **PMEMCTO_LOG_LEVEL** The value of **PMEMCTO_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **PMEMCTO_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. The same information may be retrieved using _UW(pmemcto_errormsg). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **libpmemcto** developers. Unless **PMEMCTO_LOG_FILE** is set, debugging output is written to *stderr*. + **PMEMCTO_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **PMEMCTO_LOG_FILE** is not set, the logging output is written to *stderr*. See also **libpmem**(7) for information on other environment variables that may affect **libpmemcto** behavior. # EXAMPLE # The following example creates a memory pool, allocates some memory to contain the string "hello, world", and then frees that memory. ```c #include #include #include #include #include #include #include /* size of the pmemcto pool -- 1 GB */ #define POOL_SIZE ((size_t)(1 << 30)) /* name of our layout in the pool */ #define LAYOUT_NAME "example_layout" struct root { char *str; char *data; }; int main(int argc, char *argv[]) { const char path[] = "/pmem-fs/myfile"; PMEMctopool *pcp; /* create the pmemcto pool or open it if already exists */ pcp = pmemcto_create(path, LAYOUT_NAME, POOL_SIZE, 0666); if (pcp == NULL) pcp = pmemcto_open(path, LAYOUT_NAME); if (pcp == NULL) { perror(path); exit(1); } /* get the root object pointer */ struct root *rootp = pmemcto_get_root_pointer(pcp); if (rootp == NULL) { /* allocate root object */ rootp = pmemcto_malloc(pcp, sizeof(*rootp)); if (rootp == NULL) { perror(pmemcto_errormsg()); exit(1); } /* save the root object pointer */ pmemcto_set_root_pointer(pcp, rootp); rootp->str = pmemcto_strdup(pcp, "Hello World!"); rootp->data = NULL; } /* ... */ pmemcto_close(pcp); } ``` See for more examples using the **libpmemcto** API. # BUGS # Unlike **libpmemobj**(3), data replication is not supported in **libpmemcto**. Thus, it is not allowed to specify replica sections in pool set files. # NOTES # Unlike the normal **malloc**(), which asks the system for additional memory when it runs out, **libpmemcto** allocates the size it is told to and never attempts to grow or shrink that memory pool. # AVAILABILITY # **libpmemcto** is part of the PMDK since version 1.4 and is available from # ACKNOWLEDGEMENTS # **libpmemcto** depends on jemalloc, written by Jason Evans, to do the heavy lifting of managing dynamic memory allocation. See: **libpmemcto** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **ndctl-create-namespace**(1), **dlclose**(2), **mmap**(2), **jemalloc**(3), **malloc**(3), **pmemcto_aligned_alloc**(3), **pmemcto_errormsg**(3), **pmemcto_malloc**(3), **pmemcto_malloc_usable_size**(3), **pmemcto_open**(3), **pmemcto_set_root_pointer**(3), **pmemcto_stats_print**(3), **pmemcto_strdup**(3), **pmemcto_wcsdup**(3), **libpmem**(7), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_aligned_alloc.3.md000066400000000000000000000067461331545616200223570ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_ALIGNED_ALLOC, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_aligned_alloc.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[ERRORS](#errors)
[SEE ALSO](#see-also)
# NAME # pmemcto_aligned_alloc -- allocate aligned memory # SYNOPSIS # ```c #include void *pmemcto_aligned_alloc(PMEMctopool *pcp, size_t alignment, size_t size); ``` # DESCRIPTION # The **pmemcto_aligned_alloc**() function provides the same semantics as **aligned_alloc**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It allocates *size* bytes from the memory pool and returns a pointer to the allocated memory. The memory is not zeroed. The memory address will be a multiple of *alignment*, which must be a power of two. # RETURN VALUE # On success, **pmemcto_aligned_alloc**() function returns a pointer to the allocated memory. If *size* is 0, then **pmemcto_aligned_alloc**() returns either NULL, or a unique pointer value that can later be successfully passed to **pmemcto_free**(3). If **pmemcto_aligned_alloc**() is unable to satisfy the allocation request, a NULL pointer is returned and *errno* is set appropriately. # ERRORS # **EINVAL** *alignment* was not a power of two. **ENOMEM** Insufficient memory available to satisfy allocation request. # SEE ALSO # **aligned_alloc**(3), **malloc**(3), **jemalloc**(3), **pmemcto_malloc**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_malloc.3.md000066400000000000000000000137331331545616200210430ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_MALLOC, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_malloc.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[ERRORS](#errors)
[NOTES](#notes)
[SEE ALSO](#see-also)
# NAME # pmemcto_malloc, pmemcto_free, pmemcto_calloc, pmemcto_realloc -- allocate and free persistent memory # SYNOPSIS # ```c #include void *pmemcto_malloc(PMEMctopool *pcp, size_t size); void pmemcto_free(PMEMctopool *pcp, void *ptr); void *pmemcto_calloc(PMEMctopool *pcp, size_t nmemb, size_t size); void *pmemcto_realloc(PMEMctopool *pcp, void *ptr, size_t size); ``` # DESCRIPTION # The **pmemcto_malloc**() function provides the same semantics as **malloc**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It allocates *size* bytes and returns a pointer to the allocated memory. *The memory is not initialized*. If *size* is 0, then **pmemcto_malloc**() returns either NULL, or a unique pointer value that can later be successfully passed to **pmemcto_free**(). The **pmemcto_free**() function provides the same semantics as **free**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It frees the memory space pointed to by *ptr*, which must have been returned by a previous call to **pmemcto_malloc**(), **pmemcto_calloc**() or **pmemcto_realloc**() for *the same pool of memory*. Undefined behavior occurs if frees do not correspond to allocated memory from the same memory pool. If *ptr* is NULL, no operation is performed. The **pmemcto_calloc**() function provides the same semantics as **calloc**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It allocates memory for an array of *nmemb* elements of *size* bytes each and returns a pointer to the allocated memory. The memory is set to zero. If *nmemb* or *size* is 0, then **pmemcto_calloc**() returns either NULL, or a unique pointer value that can later be successfully passed to **pmemcto_free**(). The **pmemcto_realloc**() function provides the same semantics as **realloc**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It changes the size of the memory block pointed to by *ptr* to *size* bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will *not* be initialized. If *ptr* is NULL, then the call is equivalent to *pmemcto_malloc(pcp, size)*, for all values of *size*; if *size* is equal to zero and *ptr* is not NULL, then the call is equivalent to *pmemcto_free(pcp, ptr)*. Unless *ptr* is NULL, it must have been returned by an earlier call to **pmemcto_malloc**(), **pmemcto_calloc**(), **pmemcto_realloc**() or **pmemcto_aligned_alloc**(3). If the area pointed to was moved, a *pmemcto_free(pcp, ptr)* is done. # RETURN VALUE # On success, **pmemcto_malloc**() and **pmemcto_calloc**() functions return a pointer to the allocated memory. If the allocation request cannot be satisfied, a NULL pointer is returned and *errno* is set appropriately. The **pmemcto_free**() function returns no value. On success, **pmemcto_realloc**() function returns a pointer to the newly allocated memory, or NULL if it is unable to satisfy the allocation request. If *size* was equal to 0, either NULL or a pointer suitable to be passed to **pmemcto_free**() is returned. If **pmemcto_realloc**() fails the original block is left untouched; it is not freed or moved. # ERRORS # **ENOMEM** Insufficient memory available to satisfy allocation request. # NOTES # Unlike the normal **malloc**(), which asks the system for additional memory when it runs out, **libpmemcto**(7) allocates the size it is told to and never attempts to grow or shrink that memory pool. # SEE ALSO # **jemalloc**(3), **malloc**(3), **pmemcto_aligned_alloc**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_malloc_usable_size.3.md000066400000000000000000000062011331545616200234200ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_MALLOC_USABLE_SIZE, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_malloc_usable_size.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # pmemcto_malloc_usable_size -- obtain size of block of memory allocated from pool # SYNOPSIS # ```c #include size_t pmemcto_malloc_usable_size(PMEMctopool *pcp, void *ptr); ``` # DESCRIPTION # The **pmemcto_malloc_usable_size**() function provides the same semantics as **malloc_usable_size**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It returns the number of usable bytes in the block of allocated memory pointed to by *ptr*, a pointer to a block of memory allocated by **pmemcto_malloc**(3) or a related function. # RETURN VALUE # The **pmemcto_malloc_usable_size**() function returns the number of usable bytes in the block of allocated memory pointed to by *ptr*. If *ptr* is NULL, 0 is returned. # SEE ALSO # **jemalloc**(3), **malloc**(3), **malloc_usable_size**(3), **pmemcto_malloc**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_open.3.md000066400000000000000000000221361331545616200205320ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_OPEN, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_open.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[ERRORS](#errors)
[CAVEATS](#caveats)
[BUGS](#bugs)
[SEE ALSO](#see-also)
# NAME # _UW(pmemcto_create), _UW(pmemcto_open), **pmemcto_close**(), _UW(pmemcto_check) -- create, open, close and validate close-to-open persistence pool # SYNOPSIS # ```c #include _UWFUNCR1(PMEMctopool, *pmemcto_create, *path, =q=const char *layout, size_t poolsize, mode_t mode=e=) _UWFUNCR1(PMEMctopool, *pmemcto_open, *path, const char *layout) void pmemcto_close(PMEMctopool *pcp); _UWFUNCR1(int, pmemcto_check, *path, const char *layout) ``` _UNICODE() # DESCRIPTION # The _UW(pmemcto_create) function creates a close-to-open persistence pool with the given total *poolsize*. The resulting pool is then used with functions like **pmemcto_malloc**(3) and **pmemcto_free**(3) to provide the familiar *malloc-like* programming model for the memory pool. *path* specifies the name of the memory pool file to be created. *layout* specifies the application's layout type in the form of a string. The layout name is not interpreted by **libpmemcto**(7), but may be used as a check when _UW(pmemcto_open) is called. The layout name, including the terminating null byte ('\\0'), cannot be longer than **PMEMCTO_MAX_LAYOUT** as defined in **\**. A NULL *layout* is equivalent to using an empty string as a layout name. *mode* specifies the permissions to use when creating the file, as described by **creat**(2). The memory pool file is fully allocated to the size *poolsize* using **posix_fallocate**(3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling _UW(pmemcto_create), and then specifying *poolsize* as zero. In this case _UW(pmemcto_create) will take the pool size from the size of the existing file and will verify that the file appears to be empty by searching for any non-zero data in the pool header at the beginning of the file. The minimum net pool size allowed by the library for a local close-to-open persistence pool is defined in **\** as **PMEMCTO_MIN_POOL**. Depending on the configuration of the system, the available non-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemcto memory pool could be limited by the capacity of a single memory device. **libpmemcto**(7) allows building a close-to-open persistence pool spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a *pool set* may be stored on a different memory device or pmem-aware filesystem. Creation of all the parts of the pool set can be done with _UW(pmemcto_create); however, the recommended method for creating pool sets is by using the **pmempool**(1) utility. When creating a pool set consisting of multiple files, the *path* argument passed to _UW(pmemcto_create) must point to the special *set* file that defines the pool layout and the location of all the parts of the pool set. The *poolsize* argument must be 0. The meaning of the *layout* and *mode* arguments does not change, except that the same *mode* is used for creation of all the parts of the pool set. For more information on pool set format, see **poolset**(5). The _UW(pmemcto_open) function opens an existing close-to-open persistence memory pool. *path* must be an existing file containing a pmemcto memory pool as created by _UW(pmemcto_create). If *layout* is non-NULL, it is compared to the layout name provided to _UW(pmemcto_create) when the pool was first created. This can be used to verify that the layout of the pool matches what was expected. The application must have permission to open the file and memory map it with read/write permissions. The **pmemcto_close**() function closes the memory pool indicated by *pcp* and deletes the memory pool handle. The close-to-open memory pool itself lives on in the file that contains it and may be re-opened at a later time using _UW(pmemcto_open) as described above. If the pool was not closed gracefully due to abnormal program termination or power failure, the pool is in an inconsistent state causing subsequent pool opening to fail. The _UW(pmemcto_check) function performs a consistency check of the file indicated by *path*, and returns 1 if the memory pool is found to be consistent. If the pool is found not to be consistent, further use of the file with **libpmemcto**(7) will result in undefined behavior. The debug version of **libpmemcto**(7) will provide additional details on inconsistencies when **PMEMCTO_LOG_LEVEL** is at least 1, as described in the **DEBUGGING AND ERROR HANDLING** section of **libpmemcto**(7). _UW(pmemcto_check) will return -1 and set *errno* if it cannot perform the consistency check due to other errors. _UW(pmemcto_check) opens the given *path* read-only so it never makes any changes to the file. This function is not supported on Device DAX. # RETURN VALUE # On success, _UW(pmemcto_create) returns a *PMEMctopool\** handle to the close-to-open persistence memory pool. On error, it returns NULL and sets *errno* appropriately. On success, _UW(pmemcto_open) returns a *PMEMctopool\** handle that can be used with most of the functions in **libpmemcto**(7). On error, it returns NULL and sets *errno* appropriately. The **pmemcto_close**() function returns no value. _UW(pmemcto_check) returns 1 if the memory pool is found to be consistent. If the check is successfully performed but the pool is found to be inconsistent, _UW(pmemcto_check) returns 0. If the consistency check cannot be performed, _UW(pmemcto_check) returns -1 and sets *errno* appropriately. This includes the case where *layout* is non-NULL and does not match the layout string given when the pool was created. # ERRORS # **EINVAL** "layout" string does not match the layout stored in pool header. **EINVAL** "layout" string is longer than **PMEMCTO_MAX_LAYOUT**. **EINVAL** *poolsize* is less than **PMEMCTO_MIN_POOL**. **EINVAL** Invalid format of the pool set file. **EINVAL** Invalid pool header. **EEXIST** *path* passed to _UW(pmemcto_create) points to a pool set file, but *poolsize* is not zero. **EEXIST** *path* passed to _UW(pmemcto_create) points to an existing file, but *poolsize* is not zero. **EEXIST** *path* passed to _UW(pmemcto_create) points to an existing file, which is not-empty. **EAGAIN** The pmemcto pool pointed by *path* is already open. **EACCES** No write access permission to the pool file(s). **ENOMEM** The pool cannot be mapped at the address it was created. # CAVEATS # Not all file systems support **posix_fallocate**(3). _UW(pmemcto_create) will fail if the underlying file system does not support **posix_fallocate**(3). # BUGS # Unlike **libpmemobj**(7), data replication is not supported in **libpmemcto**(7). Thus, it is not allowed to specify replica sections in pool set files. # SEE ALSO # **ndctl-create-namespace**(1), **pmempool-create**(1), **jemalloc**(3), **poolset**(5), **libpmemcto**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_set_root_pointer.3.md000066400000000000000000000071341331545616200231700ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_SET_ROOT_POINTER, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_set_root_pointer.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # pmemcto_set_root_pointer, pmemcto_get_root_pointer -- set or obtain the root object pointer # SYNOPSIS # ```c #include void pmemcto_set_root_pointer(PMEMctopool *pcp, void *ptr); void *pmemcto_get_root_pointer(PMEMctopool *pcp); ``` # DESCRIPTION # The root object of persistent memory pool is an entry point for all other persistent objects allocated using the **libpmemcto**(7) APIs. In other words, every single object stored in persistent memory pool should have the root object at the end of its reference path. There is exactly one root object in each pool. The **pmemcto_set_root_pointer**() function saves the pointer to the root object in given pool. The *ptr* must have been returned by a previous call to **pmemcto_malloc**(3), **pmemcto_calloc**(3), **pmemcto_realloc**(3) or **pmemcto_aligned_alloc**(3) for *the same pool of memory*. The **pmemcto_get_root_pointer**() function returns the pointer to the root object in given pool, or NULL if the root pointer was never set. # RETURN VALUE # The **pmemcto_set_root_pointer**() function returns no value. The **pmemcto_get_root_pointer**() function returns the pointer to the root object in given pool, or NULL if the root pointer was never set. # SEE ALSO # **pmemcto_aligned_alloc**(3), **pmemcto_calloc**(3), **pmemcto_malloc**(3), **pmemcto_realloc**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_stats_print.3.md000066400000000000000000000070261331545616200221440ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_STATS_PRINT, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_stats_print.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[SEE ALSO](#see-also)
# NAME # pmemcto_stats_print -- write human-readable memory pool statistics # SYNOPSIS # ```c #include void pmemcto_stats_print(PMEMctopool *pcp, const char *opts); ``` # DESCRIPTION # The **pmemcto_stats_print**() function produces messages containing statistics about the given memory pool. The output is printed using **libpmemcto**(7) internal *print_func* function (see **pmemcto_set_funcs**(3)). That means the output typically appears on *stderr* unless the caller supplies a replacement *print_func* or sets the environment variable **PMEMCTO_LOG_FILE** to direct output elsewhere. The *opts* string can either be NULL or it can contain a list of options that change the stats printed. General information that never changes during execution can be omitted by specifying "g" as a character within the opts string. The characters "m" and "a" can be specified to omit merged arena and per arena statistics, respectively; "b" and "l" can be specified to omit per size class statistics for bins and large objects, respectively. Unrecognized characters are silently ignored. Note that thread caching may prevent some statistics from being completely up to date. See **jemalloc**(3) for more detail (the description of the available *opts* above was taken from that man page). # SEE ALSO # **jemalloc**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_strdup.3.md000066400000000000000000000064201331545616200211100ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_STRDUP, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_strdup.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[ERRORS](#errors)
[SEE ALSO](#see-also)
# NAME # pmemcto_strdup -- duplicate a string # SYNOPSIS # ```c #include char *pmemcto_strdup(PMEMctopool *pcp, const char *s); ``` # DESCRIPTION # The **pmemcto_strdup**() function provides the same semantics as **strdup**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It returns a pointer to a new string which is a duplicate of the string *s*. Memory for the new string is obtained with **pmemcto_malloc**(3), on the given memory pool, and can be freed with **pmemcto_free**(3) on the same memory pool. # RETURN VALUE # On success, the **pmemcto_strdup**() function returns a pointer to the duplicated string. If **pmemcto_strdup**() is unable to satisfy the allocation request, a NULL pointer is returned and *errno* is set appropriately. # ERRORS # **ENOMEM** Insufficient memory available to allocate duplicated string. # SEE ALSO # **jemalloc**(3), **malloc**(3), **strdup**(3), **wcsdup**(3), **pmemcto_malloc**(3), **pmemcto_wcsdup**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemcto/pmemcto_wcsdup.3.md000066400000000000000000000064521331545616200211010ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMCTO_WCSDUP, 3) collection: libpmemcto header: PMDK date: libpmemcto API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemcto_wcsdup.3 -- man page for libpmemcto) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[ERRORS](#errors)
[SEE ALSO](#see-also)
# NAME # pmemcto_wcsdup -- duplicate a wide-char string # SYNOPSIS # ```c #include wchar_t *pmemcto_wcsdup(PMEMctopool *pcp, const wchar_t *s); ``` # DESCRIPTION # The **pmemcto_wcsdup**() function provides the same semantics as **wcsdup**(3), but operates on the memory pool *pcp* instead of the process heap supplied by the system. It returns a pointer to a new wide-char string which is a duplicate of the string *s*. Memory for the new string is obtained with **pmemcto_malloc**(3), on the given memory pool, and can be freed with **pmemcto_free**(3) on the same memory pool. # RETURN VALUE # On success, the **pmemcto_wcsdup**() function returns a pointer to the duplicated string. If **pmemcto_wcsdup**() is unable to satisfy the allocation request, a NULL pointer is returned and *errno* is set appropriately. # ERRORS # **ENOMEM** Insufficient memory available to allocate duplicated string. # SEE ALSO # **jemalloc**(3), **malloc**(3), **strdup**(3), **wcsdup**(3), **pmemcto_malloc**(3), **pmemcto_strdup**(3), **libpmemcto**(7) and **** pmdk-1.4.1/doc/libpmemlog/000077500000000000000000000000001331545616200153525ustar00rootroot00000000000000pmdk-1.4.1/doc/libpmemlog/libpmemlog.7.md000066400000000000000000000310331331545616200201700ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBPMEMLOG, 7) collection: libpmemlog header: PMDK date: pmemlog API version 1.1 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libpmemlog.7 -- man page for libpmemlog) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[CAVEATS](#caveats)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[MANAGING LIBRARY BEHAVIOR](#managing-library-behavior-1)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[BUGS](#bugs)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also) # NAME # **libpmemlog** -- persistent memory resident log file # SYNOPSIS # ```c #include cc ... -lpmemlog -lpmem ``` _UNICODE() ##### Library API versioning: ##### ```c _UWFUNC(pmemlog_check_version, =q= unsigned major_required, unsigned minor_required=e=) ``` ##### Managing library behavior: ##### ```c void pmemlog_set_funcs( void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s)); ``` ##### Error handling: ##### ```c _UWFUNCR(int, pmemlog_check, *path) ``` ##### Other library functions: ##### A description of other **libpmemlog** functions can be found on the following manual pages: **pmemlog_create**(3), **pmemlog_nbyte**(3), **pmemlog_append**(3), **pmemlog_tell**(3) # DESCRIPTION # **libpmemlog** provides a log file in *persistent memory* (pmem) such that additions to the log are appended atomically. This library is intended for applications using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of *non-volatile memory DIMMs* (NVDIMMs) provide this type of byte addressable access to storage. A *persistent memory aware file system* is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in the load/store, non-paged access to pmem. **libpmemlog** builds on thistype of memory mapped file. This library is for applications that need a persistent log file updated atomically (the updates cannot be *torn* by program interruption such as power failures). This library builds on the low-level pmem support provided by **libpmem**(7), handling the transactional update of the log, flushing to persistence, and recovery for the application. **libpmemlog** is one of a collection of persistent memory libraries available. The others are: + **libpmemobj**(7), a general use persistent memory API, providing memory allocation and transactional operations on variable-sized objects. + **libpmemblk**(7), providing pmem-resident arrays of fixed-sized blocks with atomic updates. + **libpmemcto**(7), providing close-to-open persistence. + **libpmem**(7), low-level persistent memory support. Under normal usage, **libpmemlog** will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under **DEBUGGING AND ERROR HANDLING** below. To use the pmem-resident log file provided by **libpmemlog**, a *memory pool* is first created. This is done with the **pmemlog_create**(3) function. The other functions mentioned above in SYNOPSIS section then operate on the resulting log memory pool. Once created, the memory pool is represented by an opaque handle, of type *PMEMlogpool\**, which is passed to most of the other functions from **libpmemlog**. Internally, **libpmemlog** will use either **pmem_persist**(3) or **msync**(2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the **pmem_is_pmem**(3) function in **libpmem**(7) for more information). There is no need for applications to flush changes directly when using the log memory API provided by **libpmemlog**. # CAVEATS # **libpmemlog** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The _UW(pmemlog_check_version) function is used to determine whether the installed **libpmemlog** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information provided by defines in **\**, like this: ```c reason = _U(pmemlog_check_version)(PMEMLOG_MAJOR_VERSION, PMEMLOG_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. On success, _UW(pmemlog_check_version) returns NULL. Otherwise, the return value is a static string describing the reason the version check failed. The string returned by _UW(pmemlog_check_version) must not be modified or freed. # MANAGING LIBRARY BEHAVIOR # The **pmemlog_set_funcs**() function allows an application to override memory allocation calls used internally by **libpmemlog**. Passing in NULL for any of the handlers will cause the **libpmemlog** default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4-8 kilobytes for each memory pool in use. # DEBUGGING AND ERROR HANDLING # The _UW(pmemlog_errormsg) function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libpmemlog** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libpmemlog** are typically available on a development system. The normal version, accessed when a program is linked using the **-lpmemlog** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version of **libpmemlog**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the environment variable **LD_LIBRARY_PATH** to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **PMEMLOG_LOG_LEVEL** The value of **PMEMLOG_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **PMEMLOG_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. The same information may be retrieved using _UW(pmemlog_errormsg). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **libpmemlog** developers. Unless **PMEMLOG_LOG_FILE** is set, debugging output is written to *stderr*. + **PMEMLOG_LOG_FILE** Specifies the name of a file name where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **PMEMLOG_LOG_FILE** is not set, logging output is written to *stderr*. See also **libpmem**(7) for information about other environment variables affecting **libpmemlog** behavior. # EXAMPLE # The following example illustrates how the **libpmemlog** API is used. ```c #include #include #include #include #include #include #include /* size of the pmemlog pool -- 1 GB */ #define POOL_SIZE ((size_t)(1 << 30)) /* * printit -- log processing callback for use with pmemlog_walk() */ int printit(const void *buf, size_t len, void *arg) { fwrite(buf, len, 1, stdout); return 0; } int main(int argc, char *argv[]) { const char path[] = "/pmem-fs/myfile"; PMEMlogpool *plp; size_t nbyte; char *str; /* create the pmemlog pool or open it if it already exists */ plp = _U(pmemlog_create)(path, POOL_SIZE, 0666); if (plp == NULL) plp = _U(pmemlog_open)(path); if (plp == NULL) { perror(path); exit(1); } /* how many bytes does the log hold? */ nbyte = pmemlog_nbyte(plp); printf("log holds %zu bytes", nbyte); /* append to the log... */ str = "This is the first string appended"; if (pmemlog_append(plp, str, strlen(str)) < 0) { perror("pmemlog_append"); exit(1); } str = "This is the second string appended"; if (pmemlog_append(plp, str, strlen(str)) < 0) { perror("pmemlog_append"); exit(1); } /* print the log contents */ printf("log contains:"); pmemlog_walk(plp, 0, printit, NULL); pmemlog_close(plp); } ``` See for more examples using the **libpmemlog** API. # BUGS # Unlike **libpmemobj**(7), data replication is not supported in **libpmemlog**. Thus, specifying replica sections in pool set files is not allowed. # ACKNOWLEDGEMENTS # **libpmemlog** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **msync**(2), **pmemlog_append**(3), **pmemlog_create**(3), **pmemlog_nbyte**(3), **pmemlog_tell**(3), **strerror**(3), **libpmem**(7), **libpmemblk**(7), **libpmemcto**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemlog/pmemlog_append.3.md000066400000000000000000000075141331545616200210330ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMLOG_APPEND, 3) collection: libpmemlog header: PMDK date: pmemlog API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemlog_append.3 -- man page for pmemlog_append and pmemlog_appendv functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[NOTES](#notes)
[SEE ALSO](#see-also)
# NAME # **pmemlog_append**(), **pmemlog_appendv**() -- append bytes to the persistent memory resident log file # SYNOPSIS # ```c #include int pmemlog_append(PMEMlogpool *plp, const void *buf, size_t count); int pmemlog_appendv(PMEMlogpool *plp, const struct iovec *iov, int iovcnt); ``` # DESCRIPTION # The **pmemlog_append**() function appends *count* bytes from *buf* to the current write offset in the log memory pool *plp*. Calling this function is analogous to appending to a file. The append is atomic and cannot be torn by a program failure or system crash. The **pmemlog_appendv**() function appends to the log memory pool *plp* from the scatter/gather list *iov* in a manner similar to **writev**(2). The entire list of buffers is appended atomically, as if the buffers in *iov* were concatenated in order. The append is atomic and cannot be torn by a program failure or system crash. # RETURN VALUE # On success, **pmemlog_append**() and **pmemlog_appendv**() return 0. On error, they return -1 and set *errno* appropriately. # ERRORS # **EINVAL** The vector count *iovcnt* is less than zero. **ENOSPC** There is no room for the data in the log file. **EROFS** The log file is open in read-only mode. # NOTES # Since **libpmemlog**(3) is designed as a low-latency code path, many of the checks routinely done by the operating system for **writev**(2) are not practical in the library's implementation of **pmemlog_appendv**(). No attempt is made to detect NULL or incorrect pointers, for example. # SEE ALSO # **writev**(2), **libpmemlog**(7) and **** pmdk-1.4.1/doc/libpmemlog/pmemlog_create.3.md000066400000000000000000000165661331545616200210360ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMLOG_CREATE, 3) collection: libpmemlog header: PMDK date: pmemlog API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemlog_create.3 -- man page for libpmemlog create, open, close and validate) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[CAVEATS](#caveats)
[SEE ALSO](#see-also)
# NAME # _UW(pmemlog_create), _UW(pmemlog_open), **pmemlog_close**(), _UW(pmemlog_check) -- create, open, close and validate persistent memory resident log file # SYNOPSIS # ```c #include _UWFUNCR(PMEMlogpool, *pmemlog_open, *path) _UWFUNCR1(PMEMlogpool, *pmemlog_create, *path, =q=size_t poolsize, mode_t mode=e=) void pmemlog_close(PMEMlogpool *plp); _UWFUNCR(int, pmemlog_check, *path) ``` _UNICODE() # DESCRIPTION # The _UW(pmemlog_create) function creates a log memory pool with the given total *poolsize*. Since the transactional nature of a log memory pool requires some space overhead in the memory pool, the resulting available log size is less than *poolsize*, and is made available to the caller via the **pmemlog_nbyte**(3) function. *path* specifies the name of the memory pool file to be created. *mode* specifies the permissions to use when creating the file as described by **creat**(2). The memory pool file is fully allocated to the size *poolsize* using **posix_fallocate**(3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling _UW(pmemlog_create) and then specifying *poolsize* as zero. In this case _UW(pmemlog_create) will take the pool size from the size of the existing file and will verify that the file appears to be empty by searching for any non-zero data in the pool header at the beginning of the file. The net pool size of a pool file is equal to the file size. The minimum net pool size allowed by the library for a log pool is defined in **\** as **PMEMLOG_MIN_POOL**. Depending on the configuration of the system, the available non-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemlog memory pool could be limited by the capacity of a single memory device. **libpmemlog**(7) allows building persistent memory resident logs spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a *pool set* may be stored on a different memory device or pmem-aware filesystem. Creation of all the parts of the pool set can be done with _UW(pmemlog_create); however, the recommended method for creating pool sets is with the **pmempool**(1) utility. When creating a pool set consisting of multiple files, the *path* argument passed to _UW(pmemlog_create) must point to the special *set* file that defines the pool layout and the location of all the parts of the pool set. The *poolsize* argument must be 0. The meaning of the *mode* argument does not change, except that the same *mode* is used for creation of all the parts of the pool set. The set file is a plain text file, the structure of which is described in **poolset**(5). The _UW(pmemlog_open) function opens an existing log memory pool. Similar to _UW(pmemlog_create), *path* must identify either an existing log memory pool file, or the *set* file used to create a pool set. The application must have permission to open the file and memory map the file or pool set with read/write permissions. The **pmemlog_close**() function closes the memory pool indicated by *plp* and deletes the memory pool handle. The log memory pool itself lives on in the file that contains it and may be re-opened at a later time using _UW(pmemlog_open) as described above. The _UW(pmemlog_check) function performs a consistency check of the file indicated by *path*. _UW(pmemlog_check) opens the given *path* read-only so it never makes any changes to the file. This function is not supported on Device DAX. # RETURN VALUE # On success, _UW(pmemlog_create) returns a *PMEMlogpool\** handle to the memory pool that is used with most of the functions from **libpmemlog**(7). If an error prevents any of the pool set files from being created, it returns NULL and sets *errno* appropriately. On success, _UW(pmemlog_open) returns a *PMEMlogpool\** handle to the memory pool that is used with most of the functions from **libpmemlog**(7). If an error prevents the pool from being opened, or a pool set is being opened and the actual size of any file does not match the corresponding part size defined in the *set* file, _UW(pmemlog_open) returns NULL and sets *errno* appropriately. The **pmemlog_close**() function returns no value. The _UW(pmemlog_check) function returns 1 if the persistent memory resident log file is found to be consistent. Any inconsistencies will cause _UW(pmemlog_check) to return 0, in which case the use of the file with **libpmemlog** will result in undefined behavior. The debug version of **libpmemlog** will provide additional details on inconsistencies when **PMEMLOG_LOG_LEVEL** is at least 1, as described in the **DEBUGGING AND ERROR HANDLING** section in **libpmemlog**(7). _UW(pmemlog_check) will return -1 and set *errno* if it cannot perform the consistency check due to other errors. # CAVEATS # Not all file systems support **posix_fallocate**(3). _UW(pmemlog_create) will fail if the underlying file system does not support **posix_fallocate**(3). # SEE ALSO # **pmempool**(1), **creat**(2), **posix_fallocate**(3), **pmemlog_nbyte**(3), **poolset**(5), **libpmemlog**(7) and **** pmdk-1.4.1/doc/libpmemlog/pmemlog_nbyte.3.md000066400000000000000000000054361331545616200207060ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMLOG_NBYTE, 3) collection: libpmemlog header: PMDK date: pmemlog API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemlog_nbyte.3 -- man page for pmemlog_nbyte function) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemlog_nbyte**() -- checks the amount of usable space in the log pool. # SYNOPSIS # ```c #include size_t pmemlog_nbyte(PMEMlogpool *plp); ``` # DESCRIPTION # The **pmemlog_nbyte**() function checks the amount of usable space in the log *plp*. This function may be used on a log to determine how much usable space is available after **libpmemlog**(7) has added its metadata to the memory pool. # RETURN VALUE # The **pmemlog_nbyte**() function returns the amount of usable space in the log *plp*. # SEE ALSO # **libpmemlog**(7) and **** pmdk-1.4.1/doc/libpmemlog/pmemlog_tell.3.md000066400000000000000000000103741331545616200205220ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMLOG_TELL, 3) collection: libpmemlog header: PMDK date: pmemlog API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemlog_tell.3 -- man page for pmemlog_tell, pmemlog_rewind and pmemlog_walk functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemlog_tell**(), **pmemlog_rewind**(), **pmemlog_walk**() -- checks current write point for the log or walks through the log # SYNOPSIS # ```c #include long long pmemlog_tell(PMEMlogpool *plp); void pmemlog_rewind(PMEMlogpool *plp); void pmemlog_walk(PMEMlogpool *plp, size_t chunksize, int (*process_chunk)(const void *buf, size_t len, void *arg), void *arg); ``` # DESCRIPTION # The **pmemlog_tell**() function returns the current write point for the log, expressed as a byte offset into the usable log space in the memory pool. This offset starts off as zero on a newly-created log, and is incremented by each successful append operation. This function can be used to determine how much data is currently in the log. The **pmemlog_rewind**() function resets the current write point for the log to zero. After this call, the next append adds to the beginning of the log. The **pmemlog_walk**() function walks through the log *plp*, from beginning to end, calling the callback function *process_chunk* for each *chunksize* block of data found. The argument *arg* is also passed to the callback to help avoid the need for global state. The *chunksize* argument is useful for logs with fixed-length records and may be specified as 0 to cause a single call to the callback with the entire log contents passed as the *buf* argument. The *len* argument tells the *process_chunk* function how much data *buf* is holding. The callback function should return 1 if **pmemlog_walk**() should continue walking through the log, or 0 to terminate the walk. The callback function is called while holding **libpmemlog**(7) internal locks that make calls atomic, so the callback function must not try to append to the log itself or deadlock will occur. # RETURN VALUE # On success, **pmemlog_tell**() returns the current write point for the log. On error, it returns -1 and sets *errno* appropriately. The **pmemlog_rewind**() and **pmemlog_walk**() functions return no value. # SEE ALSO # **libpmemlog**(7) and **** pmdk-1.4.1/doc/libpmemobj/000077500000000000000000000000001331545616200153435ustar00rootroot00000000000000pmdk-1.4.1/doc/libpmemobj/libpmemobj.7.md000066400000000000000000000261761331545616200201660ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBPMEMOBJ, 7) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libpmemobj.7 -- man page for libpmemobj) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[MANAGING LIBRARY BEHAVIOR](#managing-library-behavior)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also)
# NAME # **libpmemobj** -- persistent memory transactional object store # SYNOPSIS # ```c #include cc _WINUX(,-std=gnu99) ... -lpmemobj -lpmem ``` _UNICODE() ##### Library API versioning: ##### ```c _UWFUNC(pmemobj_check_version, =q= unsigned major_required, unsigned minor_required=e=) ``` ##### Managing library behavior: ##### ```c void pmemobj_set_funcs( void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s)); ``` ##### Error handling: ##### ```c _UWFUNC(pmemobj_errormsg, void) ``` ##### Other library functions: ##### A description of other **libpmemobj** functions can be found on the following manual pages: + create, open, close and validate: **pmemobj_open**(3) + low-level memory manipulation: **pmemobj_memcpy_persist**(3) + locking: **pmemobj_mutex_zero**(3) + persistent object identifier: **OID_IS_NULL**(3) + type-safety: **TOID_DECLARE**(3) + layout declaration: **POBJ_LAYOUT_BEGIN**(3) + non-transactional atomic allocations: **pmemobj_alloc**(3) + root object management: **pmemobj_root**(3) + object containers: **pmemobj_first**(3) + non-transactional persistent atomic circular doubly-linked list: **pmemobj_list_insert**(3), **POBJ_LIST_HEAD**(3) + transactional object manipulation: **pmemobj_tx_begin**(3), **pmemobj_tx_add_range**(3), **pmemobj_tx_alloc**(3) + control and statistics: **pmemobj_ctl_get**(3) + delayed atomicity actions: **pmemobj_action**(3) (EXPERIMENTAL) # DESCRIPTION # **libpmemobj** provides a transactional object store in *persistent memory* (pmem) for applications that require transactions and persistent memory management using direct access storage (DAX), which is storage that supports load/store access without paging blocks from a block storage device. Some types of *non-volatile memory DIMMs* (NVDIMMs) provide this type of byte addressable access to storage. A *persistent memory aware file system* is typically used to expose the direct access to applications. Memory mapping a file from this type of file system results in load/store, non-paged access to pmem. **libpmemobj** builds on this type of memory mapped file using the low-level pmem support provided by **libpmem**(7), handling the transactional updates, flushing changes to persistence, and managing recovery for the application. _WINUX(,=q=**libpmemobj** requires the **-std=gnu99** compilation flag to build properly.=e=) **libpmemobj** is one of a collection of persistent memory libraries available. The others are: + **libpmemblk**(7), providing pmem-resident arrays of fixed-sized blocks with atomic updates. + **libpmemlog**(7), providing a pmem-resident log file. + **libpmemcto**(7), providing close-to-open persistence. + **libpmem**(7), low-level persistent memory support. Under normal usage, **libpmemobj** will never print messages or intentionally cause the process to exit. The only exception to this is the debugging information, when enabled, as described under **DEBUGGING AND ERROR HANDLING**, below. # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The _UW(pmemobj_check_version) function is used to see if the installed **libpmemobj** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = _U(pmemobj_check_version)(PMEMOBJ_MAJOR_VERSION, PMEMOBJ_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. On success, _UW(pmemobj_check_version) returns NULL. Otherwise, the return value is a static string describing the reason the version check failed. The string returned by _UW(pmemobj_check_version) must not be modified or freed. # MANAGING LIBRARY BEHAVIOR # The **pmemobj_set_funcs**() function allows an application to override memory allocation calls used internally by **libpmemobj**. Passing in NULL for any of the handlers will cause the **libpmemobj** default function to be used. The library does not make heavy use of the system malloc functions, but it does allocate approximately 4-8 kilobytes for each memory pool in use. By default, **libpmemobj** supports up to 1024 parallel transactions/allocations. For debugging purposes it is possible to decrease this value by setting the **PMEMOBJ_NLANES** environment variable to the desired limit. # DEBUGGING AND ERROR HANDLING # If an error is detected during the call to a **libpmemobj** function, the application may retrieve an error message describing the reason for the failure from _UW(pmemobj_errormsg). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libpmemobj** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libpmemobj** are typically available on a development system. The normal version, accessed when a program is linked using the **-lpmemobj** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version of **libpmemobj**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the environment variable **LD_LIBRARY_PATH** to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **PMEMOBJ_LOG_LEVEL** The value of **PMEMOBJ_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **PMEMOBJ_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. The same information may be retrieved using _UW(pmemobj_errormsg). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **libpmemobj** developers. Unless **PMEMOBJ_LOG_FILE** is set, debugging output is written to *stderr*. + **PMEMOBJ_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **PMEMOBJ_LOG_FILE** is not set, logging output is written to *stderr*. See also **libpmem**(7) to get information about other environment variables affecting **libpmemobj** behavior. # EXAMPLE # See for examples using the **libpmemobj** API. # ACKNOWLEDGEMENTS # **libpmemobj** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **OID_IS_NULL**(3), **pmemobj_alloc**(3), **pmemobj_ctl_get**(3), **pmemobj_ctl_set**(3), **pmemobj_first**(3), **pmemobj_list_insert**(3), **pmemobj_memcpy_persist**(3), **pmemobj_mutex_zero**(3), **pmemobj_open**(3), **pmemobj_root**(3), **pmemobj_tx_add_range**(3), **pmemobj_tx_alloc**(3), **pmemobj_tx_begin**(3), **POBJ_LAYOUT_BEGIN**(3), **POBJ_LIST_HEAD**(3), **strerror**(3), **TOID_DECLARE**(3), **libpmem**(7), **libpmemblk**(7), **libpmemcto**(7), **libpmemlog**(7), **libvmem**(7) and **** pmdk-1.4.1/doc/libpmemobj/oid_is_null.3.md000066400000000000000000000146121331545616200203320ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(OID_IS_NULL, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (oid_is_null.3 -- man page for persistent object identifier and functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
_WINUX(,[NOTES](#notes)
) [SEE ALSO](#see-also)
# NAME # **OID_IS_NULL**(), **OID_EQUALS**(), **pmemobj_direct**(), **pmemobj_oid**(), **pmemobj_type_num**(), **pmemobj_pool_by_oid**(), **pmemobj_pool_by_ptr**() -- functions that allow mapping operations between object addresses, object handles, oids or type numbers # SYNOPSIS # ```c #include OID_IS_NULL(PMEMoid oid) OID_EQUALS(PMEMoid lhs, PMEMoid rhs) void *pmemobj_direct(PMEMoid oid); PMEMoid pmemobj_oid(const void *addr); uint64_t pmemobj_type_num(PMEMoid oid); PMEMobjpool *pmemobj_pool_by_oid(PMEMoid oid); PMEMobjpool *pmemobj_pool_by_ptr(const void *addr); ``` # DESCRIPTION # Each object stored in a persistent memory pool is represented by an object handle of type *PMEMoid*. In practice, such a handle is a unique Object IDentifier (*OID*) of global scope, which means that two objects from different pools will never have the same *OID*. The special **OID_NULL** macro defines a NULL-like handle that does not represent any object. The size of a single object is limited by **PMEMOBJ_MAX_ALLOC_SIZE**. Thus an allocation with a requested size greater than this value will fail. An *OID* cannot be used as a direct pointer to an object. Each time the program attempts to read or write object data, it must obtain the current memory address of the object by converting its *OID* into a pointer. In contrast to the memory address, the *OID* value for given object does not change during the life of an object (except for *realloc*), and remains valid after closing and reopening the pool. For this reason, if an object contains a reference to another persistent object, for example, to build some kind of a linked data structure, the reference must be an *OID* and not a memory address. **pmemobj_direct**() returns a pointer to the *PMEMoid* object with handle *oid*. **pmemobj_oid**() returns a *PMEMoid* handle to the object pointed to by *addr*. **pmemobj_type_num**() returns the type number of the *PMEMoid* object with handle *oid*. **pmemobj_pool_by_oid**() returns a *PMEMobjpool*\* handle to the pool containing the *PMEMoid* object with handle *oid*. **pmemobj_pool_by_ptr**() returns a *PMEMobjpool*\* handle to the pool containing the address *addr*. At the time of allocation (or reallocation), each object may be assigned a number representing its type. Such a *type number* may be used to arrange the persistent objects based on their actual user-defined structure type, thus facilitating implementation of a simple run-time type safety mechanism. This also allows iterating through all the objects of a given type that are stored in the persistent memory pool. See **pmemobj_first**(3) for more information. The **OID_IS_NULL**() macro checks if *PMEMoid* represents a NULL object. The **OID_EQUALS**() macro compares two *PMEMoid* objects. # RETURN VALUE # The **pmemobj_direct**() function returns a pointer to the object represented by *oid*. If *oid* is **OID_NULL**, **pmemobj_direct**() returns NULL. The **pmemobj_oid**() function returns a *PMEMoid* handle to the object pointed to by *addr*. If *addr* is not from within a pmemobj pool, **OID_NULL** is returned. If *addr* is not the start of an object (does not point to the beginning of a valid allocation), the resulting *PMEMoid* can be safely used only with: + **pmemobj_pool_by_oid**() + **pmemobj_direct**() + **pmemobj_tx_add_range**(3) The **pmemobj_type_num**() function returns the type number of the object represented by *oid*. The **pmemobj_pool_by_oid**() function returns a handle to the pool that contains the object represented by *oid*. If the the pool is not open or *oid* is **OID_NULL**, **pmemobj_pool_by_oid**() returns NULL. The **pmemobj_pool_by_ptr**() function returns a handle to the pool that contains the address, or NULL if the address does not belong to any open pool. _WINUX(,=q= # NOTES # For performance reasons, on Linux and FreeBSD the **pmemobj_direct**() function is inlined by default. To use the non-inlined variant of **pmemobj_direct**(), define **PMEMOBJ_DIRECT_NON_INLINE** prior to the *\#include* of **\**, either with *\#define* or with the *\-D* option to the compiler.=e=) # SEE ALSO # **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_action.3.md000066400000000000000000000173631331545616200210260ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_ACTION, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017-2018, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_action.3 -- Delayed atomicity actions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[EXAMPLES](#examples)
[SEE ALSO](#see-also)
# NAME # **pmemobj_reserve**(), **pmemobj_xreserve**(), **pmemobj_set_value**(), **pmemobj_publish**(), **pmemobj_tx_publish**(), **pmemobj_cancel**(), **POBJ_RESERVE_NEW**(), **POBJ_RESERVE_ALLOC**() -- Delayed atomicity actions (EXPERIMENTAL) # SYNOPSIS # ```c #include PMEMoid pmemobj_reserve(PMEMobjpool *pop, struct pobj_action *act, size_t size, uint64_t type_num); (EXPERIMENTAL) PMEMoid pmemobj_xreserve(PMEMobjpool *pop, struct pobj_action *act, size_t size, uint64_t type_num, uint64_t flags); (EXPERIMENTAL) void pmemobj_set_value(PMEMobjpool *pop, struct pobj_action *act, uint64_t *ptr, uint64_t value); (EXPERIMENTAL) void pmemobj_publish(PMEMobjpool *pop, struct pobj_action *actv, size_t actvcnt); (EXPERIMENTAL) int pmemobj_tx_publish(struct pobj_action *actv, size_t actvcnt); (EXPERIMENTAL) pmemobj_cancel(PMEMobjpool *pop, struct pobj_action *actv, size_t actvcnt); (EXPERIMENTAL) POBJ_RESERVE_NEW(pop, t, act) (EXPERIMENTAL) POBJ_RESERVE_ALLOC(pop, t, size, act) (EXPERIMENTAL) ``` # DESCRIPTION # All of the functions described so far have an immediate effect on the persistent state of the pool, and as such, the cost of maintaining fail-safety is paid outright and, most importantly, in the calling thread. This behavior makes implementing algorithms involving relaxed consistency guarantees difficult, if not outright impossible. The following set of functions introduce a mechanism that allows one to delay the persistent publication of a set of prepared actions to an arbitrary moment in time of the execution of a program. The publication is fail-safe atomic in the scope of the entire collection of actions, but the number of said actions is limited by *POBJ_MAX_ACTIONS* constant. If a program exists without publishing the actions, or the actions are canceled, any resources reserved by those actions are released and placed back in the pool. A single action is represented by a single `struct pobj_action`. Functions that create actions take that structure by pointer, whereas functions that publish actions take array of actions and the size of the array. The actions can be created, and published, from different threads. When creating actions, the *act* argument must be non-NULL and point to a `struct pobj_action`, the structure will be populated by the function and must not be modified or deallocated until after publishing. The **pmemobj_reserve**() functions performs a transient reservation of an object. Behaves similarly to **pmemobj_alloc**(3), but performs no modification to the persistent state. The object returned by this function can be freely modified without worrying about fail-safe atomicity until the object has been published. Any modifications of the object must be manually persisted, just like in the case of the atomic API. **pmemobj_xreserve**() is equivalent to **pmemobj_reserve**(), but with an additional *flags* argument that is a bitmask of the following values: + **POBJ_XALLOC_ZERO** - zero the object + **POBJ_CLASS_ID(class_id)** - allocate the object from allocation class *class_id*. The class id cannot be 0. The **pmemobj_set_value** function prepares an action that, once published, will modify the memory location pointed to by *ptr* to *value*. The **pmemobj_publish** function publishes the provided set of actions. The publication is fail-safe atomic. Once done, the persistent state will reflect the changes contained in the actions. The *actvcnt* cannot exceed *POBJ_MAX_ACTIONS*. The **pmemobj_tx_publish** function moves the provided actions to the scope of the transaction in which it is called. Only object reservations are supported in transactional publish. Once done, the reserved objects will follow normal transactional semantics. Can only be called during *TX_STAGE_WORK*. The **pmemobj_cancel** function releases any resources held by the provided set of actions and invalidates all actions. The **POBJ_RESERVE_NEW** macro is a typed variant of **pmemobj_reserve**. The size of the reservation is determined from the provided type *t*. The **POBJ_RESERVE_ALLOC** macro is a typed variant of **pmemobj_reserve**. The *size* of the reservation is user-provided. # EXAMPLES # The following code shows atomic append of two objects into a singly linked list. ```c struct list_node { int value; PMEMoid next; }; /* statically allocate the array of actions */ struct pobj_action actv[4]; /* reserve, populate and persist the first object */ PMEMoid tail = pmemobj_reserve(pop, &actv[0], sizeof(struct list_node), 0); if (TOID_IS_NULL(tail)) return -1; D_RW(tail)->value = 1; D_RW(tail)->next = OID_NULL; pmemobj_persist(pop, D_RW(tail), sizeof(struct list_node)); /* reserve, populate and persist the second object */ PMEMoid head = pmemobj_reserve(pop, &actv[1], sizeof(struct list_node), 0); if (TOID_IS_NULL(head)) return -1; D_RW(head)->value = 2; D_RW(head)->next = tail; pmemobj_persist(pop, D_RW(head), sizeof(struct list_node)); /* create actions to set the PMEMoid to the new values */ pmemobj_set_value(pop, &actv[2], &D_RO(root)->head.pool_uuid_lo, head.pool_uuid_lo); pmemobj_set_value(pop, &actv[3], &D_RO(root)->head.off, head.off); /* atomically publish the above actions */ pmemobj_publish(pop, actv, 4); ``` # RETURN VALUE # On success, **pmemobj_reserve**() functions return a handle to the newly reserved object, otherwise an *OID_NULL* is returned. On success, **pmemobj_tx_publish**() returns 0, otherwise, stage changes to *TX_STAGE_ONABORT* and *errno* is set appropriately # SEE ALSO # **pmemobj_alloc**(3), **pmemobj_tx_alloc**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_alloc.3.md000066400000000000000000000334001331545616200206310ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_ALLOC, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_alloc.3 -- man page for non-transactional atomic allocations) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemobj_alloc**(), **pmemobj_xalloc**(), **pmemobj_zalloc**(), **pmemobj_realloc**(), **pmemobj_zrealloc**(), **pmemobj_strdup**(), **pmemobj_wcsdup**(), **pmemobj_alloc_usable_size**(), **POBJ_NEW**(), **POBJ_ALLOC**(), **POBJ_ZNEW**(), **POBJ_ZALLOC**(), **POBJ_REALLOC**(), **POBJ_ZREALLOC**(), **POBJ_FREE**() -- non-transactional atomic allocations # SYNOPSIS # ```c #include typedef int (*pmemobj_constr)(**PMEMobjpool *pop, void *ptr, void *arg); int pmemobj_alloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, uint64_t type_num, pmemobj_constr constructor, void *arg); int pmemobj_xalloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, uint64_t type_num, uint64_t flags, pmemobj_constr constructor, void *arg); (EXPERIMENTAL) int pmemobj_zalloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, uint64_t type_num); void pmemobj_free(PMEMoid *oidp); int pmemobj_realloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, uint64_t type_num); int pmemobj_zrealloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, uint64_t type_num); int pmemobj_strdup(PMEMobjpool *pop, PMEMoid *oidp, const char *s, uint64_t type_num); int pmemobj_wcsdup(PMEMobjpool *pop, PMEMoid *oidp, const wchar_t *s, uint64_t type_num); size_t pmemobj_alloc_usable_size(PMEMoid oid); POBJ_NEW(PMEMobjpool *pop, TOID *oidp, TYPE, pmemobj_constr constructor, void *arg) POBJ_ALLOC(PMEMobjpool *pop, TOID *oidp, TYPE, size_t size, pmemobj_constr constructor, void *arg) POBJ_ZNEW(PMEMobjpool *pop, TOID *oidp, TYPE) POBJ_ZALLOC(PMEMobjpool *pop, TOID *oidp, TYPE, size_t size) POBJ_REALLOC(PMEMobjpool *pop, TOID *oidp, TYPE, size_t size) POBJ_ZREALLOC(PMEMobjpool *pop, TOID *oidp, TYPE, size_t size) POBJ_FREE(TOID *oidp) ``` # DESCRIPTION # Functions described in this document provide the mechanism to allocate, resize and free objects from the persistent memory pool in a thread-safe and fail-safe manner. All the routines are atomic with respect to other threads and any power-fail interruptions. If any of these operations is torn by program failure or system crash, on recovery they are guaranteed to be entirely completed or discarded, leaving the persistent memory heap and internal object containers in a consistent state. All these functions can be used outside transactions. Note that operations performed using the non-transactional API are considered durable after completion, even if executed within an open transaction. Such non-transactional changes will not be rolled back if the transaction is aborted or interrupted. The allocations are always aligned to a cache-line boundary. The *pmemobj_constr* type represents a constructor for atomic allocation from the persistent memory heap associated with memory pool *pop*. *ptr* is a pointer to the allocated memory area and *arg* is a user-defined argument passed to the constructor. The **pmemobj_alloc**() function allocates a new object from the persistent memory heap associated with memory pool *pop*. The *PMEMoid* of the allocated object is stored in *oidp*. If *oidp* is NULL, then the newly allocated object may be accessed only by iterating objects in the object container associated with the type number *type_num*, as described in **POBJ_FOREACH**(3). If *oidp* points to a memory location from the **pmemobj** heap, *oidp* is modified atomically. Before returning, **pmemobj_alloc**() calls the *constructor* function, passing the pool handle *pop*, the pointer to the newly allocated object in *ptr*, and the *arg* argument. It is guaranteed that the allocated object is either properly initialized, or if the allocation is interrupted before the constructor completes, the memory space reserved for the object is reclaimed. *size* can be any non-zero value; however, due to internal padding and object metadata, the actual size of the allocation will differ from the requested size by at least 64 bytes. For this reason, making allocations of a size less than 64 bytes is extremely inefficient and discouraged. The allocated object is added to the internal container associated with *type_num*. **pmemobj_xalloc**() is equivalent to **pmemobj_alloc**(), but with an additional *flags* argument that is a bitmask of the following values: + **POBJ_XALLOC_ZERO** - zero the object (equivalent of **pmemobj_zalloc**()) + **POBJ_CLASS_ID(class_id)** - allocate the object from allocation class *class_id*. The class id cannot be 0. The **pmemobj_zalloc**() function allocates a new zeroed object from the persistent memory heap associated with memory pool *pop*. The *PMEMoid* of the allocated object is stored in *oidp*. If *oidp* is NULL, then the newly allocated object may be accessed only by iterating objects in the object container associated with the type number *type_num*, as described in **POBJ_FOREACH**(3). If *oidp* points to a memory location from the **pmemobj** heap, *oidp* is modified atomically. *size* can be any non-zero value; however, due to internal padding and object metadata, the actual size of the allocation will differ from the requested one by at least 64 bytes. For this reason, making allocations of a size less than 64 bytes is extremely inefficient and discouraged. The allocated object is added to the internal container associated with *type_num*. The **pmemobj_free**() function frees the memory space represented by *oidp*, which must have been allocated by a previous call to **pmemobj_alloc**(), **pmemobj_xalloc**(), **pmemobj_zalloc**(), **pmemobj_realloc**(), or **pmemobj_zrealloc**(). **pmemobj_free**() provides the same semantics as **free**(3), but instead of operating on the process heap supplied by the system, it operates on the persistent memory heap. If *oidp* is **OID_NULL**, no operation is performed. If *oidp* is NULL or if it points to the root object's *OID*, the behavior of **pmemobj_free**() is undefined. *oidp* is set to **OID_NULL** after the memory is freed. If *oidp* points to a memory location from the **pmemobj** heap, *oidp* is modified atomically. The **pmemobj_realloc**() function changes the size of the object represented by *oidp* to *size* bytes. **pmemobj_realloc**() provides similar semantics to **realloc**(3), but operates on the persistent memory heap associated with memory pool *pop*. The resized object is also added or moved to the internal container associated with type number *type_num*. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will *not* be initialized. If *oidp* is *OID_NULL*, then the call is equivalent to *pmemobj_alloc(pop, size, type_num)*. If *size* is equal to zero, and *oidp* is not **OID_NULL**, then the call is equivalent to *pmemobj_free(oid)*. Unless *oidp* is **OID_NULL**, it must have been allocated by an earlier call to **pmemobj_alloc**(), **pmemobj_xalloc**(), **pmemobj_zalloc**(), **pmemobj_realloc**(), or **pmemobj_zrealloc**(). Note that the object handle value may change as a result of reallocation. If the object was moved, the memory space represented by *oid* is reclaimed. If *oidp* points to a memory location from the **pmemobj** heap, *oidp* is modified atomically. If *oidp* is NULL or if it points to the root object's *OID*, the behavior of **pmemobj_realloc**() is undefined. **pmemobj_zrealloc**() is equivalent to **pmemobj_realloc**(), except that if the new size is larger than the old size, the added memory will be zeroed. The **pmemobj_strdup**() function stores a handle to a new object in *oidp* which is a duplicate of the string *s*. **pmemobj_strdup**() provides the same semantics as **strdup**(3), but operates on the persistent memory heap associated with memory pool *pop*. If *oidp* is NULL, then the newly allocated object may be accessed only by iterating objects in the object container associated with type number *type_num*, as described in **POBJ_FOREACH**(3). If *oidp* points to a memory location from the **pmemobj** heap, *oidp* is modified atomically. The allocated string object is also added to the internal container associated with type number *type_num*. Memory for the new string is obtained with **pmemobj_alloc**(), on the given memory pool, and can be freed with **pmemobj_free**() on the same memory pool. **pmemobj_wcsdup**() is equivalent to **pmemobj_strdup**(), but operates on a wide character string (wchar_t) rather than a standard character string. The **pmemobj_alloc_usable_size**() function provides the same semantics as **malloc_usable_size**(3), but instead of the process heap supplied by the system, it operates on the persistent memory heap. The **POBJ_NEW**() macro is a wrapper around the **pmemobj_alloc**() function. Instead of taking a pointer to *PMEMoid*, it takes a pointer to the typed *OID* of type name *TYPE*, and passes the size and type number from the typed *OID* to **pmemobj_alloc**(). The **POBJ_ALLOC**() macro is equivalent to **POBJ_NEW**, except that instead of using the size of the typed *OID*, passes *size* to **pmemobj_alloc**(). The **POBJ_ZNEW**() macro is a wrapper around the **pmemobj_zalloc**() function. Instead of taking a pointer to *PMEMoid*, it takes a pointer to the typed *OID* of type name *TYPE*, and passes the size and type number from the typed *OID* to **pmemobj_zalloc**(). The **POBJ_ZALLOC**() macro is equivalent to **POBJ_ZNEW**, except that instead of using the size of the typed *OID*, passes *size* to **pmemobj_zalloc**(). The **POBJ_REALLOC**() macro is a wrapper around the **pmemobj_realloc**() function. Instead of taking a pointer to *PMEMoid*, it takes a pointer to the typed *OID* of type name *TYPE*, and passes the type number from the typed *OID* to **pmemobj_realloc**(). The **POBJ_ZREALLOC**() macro is a wrapper around the **pmemobj_zrealloc**() function. Instead of taking a pointer to *PMEMoid*, it takes a pointer to the typed *OID* of type name *TYPE*, and passes the type number from the typed *OID* to **pmemobj_zrealloc**(). The **POBJ_FREE**() macro is a wrapper around the **pmemobj_free**() function which takes a pointer to the typed *OID* instead of to *PMEMoid*. # RETURN VALUE # On success, **pmemobj_alloc**() and **pmemobj_xalloc** return 0. If *oidp* is not NULL, the *PMEMoid* of the newly allocated object is stored in *oidp*. If the allocation fails, -1 is returned and *errno* is set appropriately. If the constructor returns a non-zero value, the allocation is canceled, -1 is returned, and *errno* is set to **ECANCELED**. If *size* equals 0, or the *flags* for **pmemobj_xalloc** are invalid, -1 is returned, *errno* is set to **EINVAL**, and *oidp* is left untouched. On success, **pmemobj_zalloc**() returns 0. If *oidp* is not NULL, the *PMEMoid* of the newly allocated object is stored in *oidp*. If the allocation fails, it returns -1 and sets *errno* appropriately. If *size* equals 0, it returns -1, sets *errno* to **EINVAL**, and leaves *oidp* untouched. The **pmemobj_free**() function returns no value. On success, **pmemobj_realloc**() and **pmemobj_zrealloc**() return 0 and update *oidp* if necessary. On error, they return -1 and set *errno* appropriately. On success, **pmemobj_strdup**() and **pmemobj_wcsdup**() return 0. If *oidp* is not NULL, the *PMEMoid* of the duplicated string object is stored in *oidp*. If *s* is NULL, they return -1, set *errno* to **EINVAL**, and leave *oidp* untouched. On other errors, they return -1 and set *errno* appropriately. The **pmemobj_alloc_usable_size**() function returns the number of usable bytes in the object represented by *oid*. If *oid* is **OID_NULL**, it returns 0. # SEE ALSO # **free**(3), **POBJ_FOREACH**(3), **realloc**(3), **strdup**(3), **wcsdup**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_ctl_get.3.md000066400000000000000000000416551331545616200211730ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_CTL_GET, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017-2018, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_ctl_get.3 -- man page for libpmemobj CTL) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[CTL NAMESPACE](#ctl-namespace)
[CTL EXTERNAL CONFIGURATION](#ctl-external-configuration)
[SEE ALSO](#see-also)
# NAME # _UW(pmemobj_ctl_get), _UW(pmemobj_ctl_set), _UW(pmemobj_ctl_exec) -- Query and modify libpmemobj internal behavior (EXPERIMENTAL) # SYNOPSIS # ```c #include _UWFUNCR2(int, pmemobj_ctl_get, PMEMobjpool *pop, *name, void *arg, =q= (EXPERIMENTAL)=e=) _UWFUNCR2(int, pmemobj_ctl_set, PMEMobjpool *pop, *name, void *arg, =q= (EXPERIMENTAL)=e=) _UWFUNCR2(int, pmemobj_ctl_exec, PMEMobjpool *pop, *name, void *arg, =q= (EXPERIMENTAL)=e=) ``` _UNICODE() # DESCRIPTION # The _UW(pmemobj_ctl_get), _UW(pmemobj_ctl_set) and _UW(pmemobj_ctl_exec) functions provide a uniform interface for querying and modifying the internal behavior of **libpmemobj** through the control (CTL) namespace. The CTL namespace is organized in a tree structure. Starting from the root, each node can be either internal, containing other elements, or a leaf. Internal nodes themselves can only contain other nodes and cannot be entry points. There are two types of those nodes: *named* and *indexed*. Named nodes have string identifiers. Indexed nodes represent an abstract array index and have an associated string identifier. The index itself is provided by the user. A collection of indexes present on the path of an entry point is provided to the handler functions as name and index pairs. The *name* argument specifies an entry point as defined in the CTL namespace specification. The entry point description specifies whether the extra *arg* is required. Those two parameters together create a CTL query. The *pop* argument is optional if the entry point resides in a global namespace (i.e., is shared for all the pools). The functions and the entry points are thread-safe unless indicated otherwise below. If there are special conditions for calling an entry point, they are explicitly stated in its description. The functions propagate the return value of the entry point. If either *name* or *arg* is invalid, -1 is returned. Entry points are the leaves of the CTL namespace structure. Each entry point can read from the internal state, write to the internal state, exec a function or a combination of these operations. The entry points are listed in the following format: name | r(ead)w(rite)x(ecute) | global/- | read argument type | write argument type | exec argument type | config argument type description... # CTL NAMESPACE # prefault.at_create | rw | global | int | int | - | boolean If set, every page of the pool will be touched and written to when the pool is created, in order to trigger page allocation and minimize the performance impact of pagefaults. Affects only the _UW(pmemobj_create) function. Always returns 0. prefault.at_open | rw | global | int | int | - | boolean If set, every page of the pool will be touched and written to when the pool is opened, in order to trigger page allocation and minimize the performance impact of pagefaults. Affects only the _UW(pmemobj_open) function. Always returns 0. tx.debug.skip_expensive_checks | rw | - | int | int | - | boolean Turns off some expensive checks performed by the transaction module in "debug" builds. Ignored in "release" builds. tx.cache.size | rw | - | long long | long long | - | integer Size in bytes of the transaction snapshot cache. In a larger cache the frequency of persistent allocations is lower, but with higher fixed cost. This should be set to roughly the sum of sizes of the snapshotted regions in an average transaction in the pool. This value must be a in a range between 0 and **PMEMOBJ_MAX_ALLOC_SIZE**. If the current threshold is larger than the new cache size, the threshold will be made equal to the new size. This entry point is not thread safe and should not be modified if there are any transactions currently running. Returns 0 if successful, -1 otherwise. tx.cache.threshold | rw | - | long long | long long | - | integer Threshold in bytes, below which snapshots will use the cache. All larger snapshots will trigger a persistent allocation. This value must be a in a range between 0 and **tx.cache.size**. This entry point is not thread safe and should not be modified if there are any transactions currently running. Returns 0 if successful, -1 otherwise. tx.post_commit.queue_depth | rw | - | int | int | - | integer Controls the depth of the post-commit tasks queue. A post-commit task is the collection of work items that need to be performed on the persistent state after a successfully completed transaction. This includes freeing no longer needed objects and cleaning up various caches. By default, this queue does not exist and the post-commit task is executed synchronously in the same thread that ran the transaction. By changing this parameter, one can offload this task to a separate worker. If the queue is full, the algorithm, instead of waiting, performs the post-commit in the current thread. The task is performed on a finite resource (lanes, of which there are 1024), and if the worker threads that process this queue are unable to keep up with the demand, regular threads might start to block waiting for that resource. This will happen if the queue depth value is too large. As a general rule, this value should be set to approximately 1024 minus the average number of threads in the application (not counting the post-commit workers); however, this may vary from workload to workload. The queue depth value must also be a power of two. This entry point is not thread-safe and must be called when no transactions are currently being executed. Returns 0 if successful, -1 otherwise. tx.post_commit.worker | r- | - | void * | - | - | - The worker function launched in a thread to perform asynchronous processing of post-commit tasks. This function returns only after a stop entry point is called. There may be many worker threads at a time. If there is no work to be done, this function sleeps instead of polling. Always returns 0. tx.post_commit.stop | r- | - | void * | - | - | - This function forces all the post-commit worker functions to exit and return control back to the calling thread. This should be called before the application terminates and the post commit worker threads need to be shutdown. After the invocation of this entry point, the post-commit task queue can no longer be used. If worker threads must be restarted after a stop, the tx.post_commit.queue_depth needs to be set again. This entry point must be called when no transactions are currently being executed. Always returns 0. heap.alloc_class.[class_id].desc | rw | - | `struct pobj_alloc_class_desc` | `struct pobj_alloc_class_desc` | - | integer, integer, integer, string Describes an allocation class. Allows one to create or view the internal data structures of the allocator. Creating custom allocation classes can be beneficial for both raw allocation throughput, scalability and, most importantly, fragmentation. By carefully constructing allocation classes that match the application workload, one can entirely eliminate external and internal fragmentation. For example, it is possible to easily construct a slab-like allocation mechanism for any data structure. The `[class_id]` is an index field. Only values between 0-254 are valid. If setting an allocation class, but the `class_id` is already taken, the function will return -1. The values between 0-127 are reserved for the default allocation classes of the library and can be used only for reading. The recommended method for retrieving information about all allocation classes is to call this entry point for all class ids between 0 and 254 and discard those results for which the function returns an error. This entry point takes a complex argument. ``` struct pobj_alloc_class_desc { size_t unit_size; size_t alignment; unsigned units_per_block; enum pobj_header_type header_type; unsigned class_id; }; ``` The first field, `unit_size`, is an 8-byte unsigned integer that defines the allocation class size. While theoretically limited only by **PMEMOBJ_MAX_ALLOC_SIZE**, for most workloads this value should be between 8 bytes and 2 megabytes. The `alignment` field is currently unsupported and must be set to 0. All objects have default alignment of 64 bytes, but the user data alignment is affected by the size of the chosen header. The `units_per_block` field defines how many units a single block of memory contains. This value will be rounded up to match the internal size of the block (256 kilobytes or a multiple thereof). For example, given a class with a `unit_size` of 512 bytes and a `units_per_block` of 1000, a single block of memory for that class will have 512 kilobytes. This is relevant because the bigger the block size, the less frequently blocks need to be fetched, resulting in lower contention on global heap state. Keep in mind that object allocation is tracked in a bitmap with a limited number of entries, making it inefficient to create allocation classes smaller than 128 bytes. The `header_type` field defines the header of objects from the allocation class. There are three types: - **POBJ_HEADER_LEGACY**, string value: `legacy`. Used for allocation classes prior to version 1.3 of the library. Not recommended for use. Incurs a 64 byte metadata overhead for every object. Fully supports all features. - **POBJ_HEADER_COMPACT**, string value: `compact`. Used as default for all predefined allocation classes. Incurs a 16 byte metadata overhead for every object. Fully supports all features. - **POBJ_HEADER_NONE**, string value: `none`. Header type that incurs no metadata overhead beyond a single bitmap entry. Can be used for very small allocation classes or when objects must be adjacent to each other. This header type does not support type numbers (type number is always 0) or allocations that span more than one unit. The `class_id` field is an optional, runtime-only variable that allows the user to retrieve the identifier of the class. This will be equivalent to the provided `[class_id]`. This field cannot be set from a config file. The allocation classes are a runtime state of the library and must be created after every open. It is highly recommended to use the configuration file to store the classes. This structure is declared in the `libpmemobj/ctl.h` header file. Please refer to this file for an in-depth explanation of the allocation classes and relevant algorithms. Allocation classes constructed in this way can be leveraged by explicitly specifying the class using **POBJ_CLASS_ID(id)** flag in **pmemobj_tx_xalloc**()/**pmemobj_xalloc**() functions. Example of a valid alloc class query string: ``` heap.alloc_class.128.desc=500,0,1000,compact ``` This query, if executed, will create an allocation class with an id of 128 that has a unit size of 500 bytes, has at least 1000 units per block and uses a compact header. For reading, function returns 0 if successful, if the allocation class does not exist it sets the errno to **ENOENT** and returns -1; For writing, function returns 0 if the allocation class has been successfully created, -1 otherwise. heap.alloc_class.new.desc | -w | - | - | `struct pobj_alloc_class_desc` | - | integer, integer, integer, string Same as `heap.alloc_class.[class_id].desc`, but instead of requiring the user to provide the class_id, it automatically creates the allocation class with the first available identifier. This should be used when it's impossible to guarantee unique allocation class naming in the application (e.g. when writing a library that uses libpmemobj). The required class identifier will be stored in the `class_id` field of the `struct pobj_alloc_class_desc`. This function returns 0 if the allocation class has been successfully created, -1 otherwise. stats.enabled | rw | - | int | int | - | boolean Enables or disables runtime collection of statistics. Statistics are not recalculated after enabling; any operations that occur between disabling and re-enabling will not be reflected in subsequent values. Statistics are disabled by default. Enabling them may have non-trivial performance impact. Always returns 0. stats.heap.curr_allocated | r- | - | int | - | - | - Returns the number of bytes currently allocated in the heap. If statistics were disabled at any time in the lifetime of the heap, this value may be inaccurate. heap.size.granularity | rw- | - | uint64_t | uint64_t | - | long long Reads or modifies the granularity with which the heap grows when OOM. Valid only if the poolset has been defined with directories. A granularity of 0 specifies that the pool will not grow automatically. This function returns 0 if the granularity value is 0, or is larger than *PMEMOBJ_MIN_PART*, -1 otherwise. heap.size.extend | --x | - | - | - | uint64_t | - Extends the heap by the given size. Must be larger than *PMEMOBJ_MIN_PART*. This function returns 0 if successful, -1 otherwise. # CTL EXTERNAL CONFIGURATION # In addition to direct function call, each write entry point can also be set using two alternative methods. The first method is to load a configuration directly from the **PMEMOBJ_CONF** environment variable. A properly formatted ctl config string is a single-line sequence of queries separated by ';': ``` query0;query1;...;queryN ``` A single query is constructed from the name of the ctl write entry point and the argument, separated by '=': ``` entry_point=entry_point_argument ``` The entry point argument type is defined by the entry point itself, but there are three predefined primitives: *) integer: represented by a sequence of [0-9] characters that form a single number. *) boolean: represented by a single character: y/n/Y/N/0/1, each corresponds to true or false. If the argument contains any trailing characters, they are ignored. *) string: a simple sequence of characters. There are also complex argument types that are formed from the primitives separated by a ',': ``` first_arg,second_arg ``` In summary, a full configuration sequence looks like this: ``` (first_entry_point)=(arguments, ...);...;(last_entry_point)=(arguments, ...); ``` As an example, to set both prefault at_open and at_create variables: ``` PMEMOBJ_CONF="prefault.at_open=1;prefault.at_create=1" ``` The second method of loading an external configuration is to set the **PMEMOBJ_CONF_FILE** environment variable to point to a file that contains a sequence of ctl queries. The parsing rules are all the same, but the file can also contain white-spaces and comments. To create a comment, simply use '#' anywhere in a line and everything afterwards, until a new line '\n', will be ignored. An example configuration file: ``` ######################### # My pmemobj configuration ######################### # # Global settings: prefault. # modify the behavior of pre-faulting at_open = 1; # prefault when the pool is opened prefault. at_create = 0; # but don't prefault when it's created # Per-pool settings: # ... ``` # SEE ALSO # **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_first.3.md000066400000000000000000000124311331545616200206670ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_FIRST, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_first.3 -- man page for pmemobj container operations) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[SEE ALSO](#see-also)
# NAME # **pmemobj_first**(), **pmemobj_next**(), **POBJ_FIRST**(), **POBJ_FIRST_TYPE_NUM**(), **POBJ_NEXT**(), **POBJ_NEXT_TYPE_NUM**(), **POBJ_FOREACH**(), **POBJ_FOREACH_SAFE**(), **POBJ_FOREACH_TYPE**(), **POBJ_FOREACH_SAFE_TYPE**() -- pmemobj container operations # SYNOPSIS # ```c #include PMEMoid pmemobj_first(PMEMobjpool *pop); PMEMoid pmemobj_next(PMEMoid oid); POBJ_FIRST(PMEMobjpool *pop, TYPE) POBJ_FIRST_TYPE_NUM(PMEMobjpool *pop, uint64_t type_num) POBJ_NEXT(TOID oid) POBJ_NEXT_TYPE_NUM(PMEMoid oid) POBJ_FOREACH(PMEMobjpool *pop, PMEMoid varoid) POBJ_FOREACH_SAFE(PMEMobjpool *pop, PMEMoid varoid, PMEMoid nvaroid) POBJ_FOREACH_TYPE(PMEMobjpool *pop, TOID var) POBJ_FOREACH_SAFE_TYPE(PMEMobjpool *pop, TOID var, TOID nvar) ``` # DESCRIPTION # The **libpmemobj**(7) container operations provide a mechanism that allows iteration through the internal object collection, either looking for a specific object, or performing a specific operation on each object of a given type. Software should not make any assumptions about the order of the objects in the internal object containers. The **pmemobj_first**() function returns the first object from the pool. The **POBJ_FIRST**() macro returns the first object from the pool of the type specified by *TYPE*. The **POBJ_FIRST_TYPE_NUM**() macro returns the first object from the pool of the type specified by *type_num*. The **pmemobj_next**() function returns the next object from the pool. The **POBJ_NEXT**() macro returns the next object of the same type as the object referenced by *oid*. The **POBJ_NEXT_TYPE_NUM**() macro returns the next object of the same type number as the object referenced by *oid*. The following four macros provide a more convenient way to iterate through the internal collections, performing a specific operation on each object. The **POBJ_FOREACH**() macro performs a specific operation on each allocated object stored in the persistent memory pool *pop*. It traverses the internal collection of all the objects, assigning a handle to each element in turn to *varoid*. The **POBJ_FOREACH_TYPE**() macro performs a specific operation on each allocated object stored in the persistent memory pool *pop* that has the same type as *var*. It traverses the internal collection of all the objects of the specified type, assigning a handle to each element in turn to *var*. The macros **POBJ_FOREACH_SAFE**() and **POBJ_FOREACH_SAFE_TYPE**() work in a similar fashion as **POBJ_FOREACH**() and **POBJ_FOREACH_TYPE**(), except that prior to performing the operation on the object, they preserve a handle to the next object in the collection by assigning it to *nvaroid* or *nvar*, respectively. This allows safe deletion of selected objects while iterating through the collection. # RETURN VALUE # **pmemobj_first**() returns the first object from the pool, or, if the pool is empty, **OID_NULL**. **pmemobj_next**() returns the next object from the pool. If the object referenced by *oid* is the last object in the collection, or if *oid* is *OID_NULL*, **pmemobj_next**() returns **OID_NULL**. # SEE ALSO # **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_list_insert.3.md000066400000000000000000000222071331545616200221010ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_LIST_INSERT, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_list_insert.3 -- man page for non-transactional persistent atomic lists) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemobj_list_insert**(), **pmemobj_list_insert_new**(), **pmemobj_list_move**(), **pmemobj_list_remove**() -- non-transactional persistent atomic lists functions # SYNOPSIS # ```c #include int pmemobj_list_insert(PMEMobjpool *pop, size_t pe_offset, void *head, PMEMoid dest, int before, PMEMoid oid); PMEMoid pmemobj_list_insert_new(PMEMobjpool *pop, size_t pe_offset, void *head, PMEMoid dest, int before, size_t size, uint64_t type_num, pmemobj_constr constructor, void arg); int pmemobj_list_move(PMEMobjpool *pop, size_t pe_old_offset, void *head_old, size_t pe_new_offset, void *head_new, PMEMoid dest, int before, PMEMoid oid); int pmemobj_list_remove(PMEMobjpool *pop, size_t pe_offset, void *head, PMEMoid oid, int free); ``` # DESCRIPTION # In addition to the container operations on internal object collections described in **pmemobj_first**(3), **libpmemobj**(7) provides a mechanism for organizing persistent objects in user-defined, persistent, atomic, circular, doubly-linked lists. All the routines and macros operating on the persistent lists provide atomicity with respect to any power-fail interruptions. If any of those operations is torn by program failure or system crash, on recovery they are guaranteed to be entirely completed or discarded, leaving the lists, persistent memory heap and internal object containers in a consistent state. The persistent atomic circular doubly linked lists support the following functionality: + Insertion of an object at the head of the list, or at the end of the list. + Insertion of an object before or after any element in the list. + Atomic allocation and insertion of a new object at the head of the list, or at the end of the list. + Atomic allocation and insertion of a new object before or after any element in the list. + Atomic moving of an element from one list to the specific location on another list. + Removal of any object in the list. + Atomic removal and freeing of any object in the list. + Forward or backward traversal through the list. A list is headed by a *list_head* structure containing the object handle of the first element on the list. The elements are doubly linked so that an arbitrary element can be removed without the need to traverse the list. New elements can be added to the list before or after an existing element, at the head of the list, or at the tail of the list. A list may be traversed in either direction. The user-defined structure of each element must contain a field of type *list_entry* that holds the object handles to the previous and next element on the list. Both the *list_head* and the *list_entry* structures are declared in **\**. The functions below are intended to be used outside transactions - transactional variants are described in manpages to functions mentioned at **TRANSACTIONAL OBJECT MANIPULATION** in **libpmemobj**(7). Note that operations performed using this non-transactional API are independent from their transactional counterparts. If any non-transactional allocations or list manipulations are performed within an open transaction, the changes will not be rolled back if such a transaction is aborted or interrupted. The list insertion and move functions use a common set of arguments to define where an object will be inserted into the list. *dest* identifies the element before or after which the object will be inserted, or, if *dest* is **OID_NULL**, indicates that the object should be inserted at the head or tail of the list. *before* determines where the object will be inserted: + **POBJ_LIST_DEST_BEFORE** - insert the element before the existing element *dest* + **POBJ_LIST_DEST_AFTER** - insert the element after the existing element *dest* + **POBJ_LIST_DEST_HEAD** - when *dest* is **OID_NULL**, insert the element at the head of the list + **POBJ_LIST_DEST_TAIL** - when *dest* is **OID_NULL**, insert the element at the tail of the list >NOTE: Earlier versions of **libpmemobj**(7) do not define **POBJ_LIST_DEST_BEFORE** and **POBJ_LIST_DEST_AFTER**. Use 1 for before, and 0 for after. The **pmemobj_list_insert**() function inserts the element represented by object handle *oid* into the list referenced by *head*, at the location specified by *dest* and *before* as described above. *pe_offset* specifies the offset of the structure that connects the elements in the list. All the handles *head*, *dest* and *oid* must point to objects allocated from memory pool *pop*. *head* and *oid* cannot be **OID_NULL**. The **pmemobj_list_insert_new**() function atomically allocates a new object of given *size* and type *type_num* and inserts it into the list referenced by *head* at the location specified by *dest* and *before* as described above. *pe_offset* specifies the offset of the structure that connects the elements in the list. The handles *head* and *dest* must point to objects allocated from memory pool *pop*. Before returning, **pmemobj_list_insert_new**() calls the *constructor* function, passing the pool handle *pop*, the pointer to the newly allocated object *ptr*, and the *arg* argument. It is guaranteed that the allocated object is either properly initialized or, if the allocation is interrupted before the constructor completes, the memory space reserved for the object is reclaimed. *head* cannot be **OID_NULL**. The allocated object is also added to the internal container associated with *type_num*, as described in **POBJ_FOREACH**(3). The **pmemobj_list_move**() function moves the object represented by object handle *oid* from the list referenced by *head_old* to the list referenced by *head_new*, inserting it at the location specified by *dest* and *before* as described above. *pe_old_offset* and *pe_new_offset* specify the offsets of the structures that connect the elements in the old and new lists, respectively. All the handles *head_old*, *head_new*, *dest* and *oid* must point to objects allocated from memory pool *pop*. *head_old*, *head_new* and *oid* cannot be **OID_NULL**. The **pmemobj_list_remove**() function removes the object represented by object handle *oid* from the list referenced by *head*. If *free* is set, it also removes the object from the internal object container and frees the associated memory space. *pe_offset* specifies the offset of the structure that connects the elements in the list. Both *head* and *oid* must point to objects allocated from memory pool *pop* and cannot be **OID_NULL**. # RETURN VALUE # On success, **pmemobj_list_insert**(), **pmemobj_list_remove**() and **pmemobj_list_move**() return 0. On error, they return -1 and set *errno* appropriately. On success, **pmemobj_list_insert_new**() returns a handle to the newly allocated object. If the constructor returns a non-zero value, the allocation is canceled, -1 is returned, and *errno* is set to **ECANCELED**. On other errors, **OID_NULL** is returned and *errno* is set appropriately. # SEE ALSO # **pmemobj_first**(3), **POBJ_FOREACH**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_memcpy_persist.3.md000066400000000000000000000134001331545616200226000ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_MEMCPY_PERSIST, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_memcpy_persist.3 -- man page for Low-level memory manipulation) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[EXAMPLES](#examples)
[SEE ALSO](#see-also)
# NAME # **pmemobj_memcpy_persist**(), **pmemobj_memset_persist**(), **pmemobj_persist**(), **pmemobj_flush**(), **pmemobj_drain**() -- low-level memory manipulation functions # SYNOPSIS # ```c #include void *pmemobj_memcpy_persist(PMEMobjpool *pop, void *dest, const void *src, size_t len); void *pmemobj_memset_persist(PMEMobjpool *pop, void *dest, int c, size_t len); void pmemobj_persist(PMEMobjpool *pop, const void *addr, size_t len); void pmemobj_flush(PMEMobjpool *pop, const void *addr, size_t len); void pmemobj_drain(PMEMobjpool *pop); ``` # DESCRIPTION # The **libpmemobj**-specific low-level memory manipulation functions described here leverage the knowledge of the additional configuration options available for **libpmemobj**(7) pools, such as replication. They also take advantage of the type of storage behind the pool and use appropriate flush/drain functions. It is advised to use these functions in conjunction with **libpmemobj**(7) objects rather than using low-level memory manipulation functions from **libpmem**. The **pmemobj_memcpy_persist**() and **pmemobj_memset_persist**() functions provide the same memory copying as their namesakes **memcpy**(3), and **memset**(3), and ensure that the result has been flushed to persistence before returning. **pmemobj_persist**() forces any changes in the range \[*addr*, *addr*+*len*) to be stored durably in persistent memory. Internally this may call either **pmem_msync**(3) or **pmem_persist**(3). There are no alignment restrictions on the range described by *addr* and *len*, but **pmemobj_persist**() may expand the range as necessary to meet platform alignment requirements. >WARNING: Like **msync**(2), there is nothing atomic or transactional about this call. Any unwritten stores in the given range will be written, but some stores may have already been written by virtue of normal cache eviction/replacement policies. Correctly written code must not depend on stores waiting until **pmemobj_persist**() is called to become persistent - they can become persistent at any time before **pmemobj_persist**() is called. The **pmemobj_flush**() and **pmemobj_drain**() functions provide partial versions of the **pmemobj_persist**() function described above. These functions allow advanced programs to create their own variations of **pmemobj_persist**(). For example, a program that needs to flush several discontiguous ranges can call **pmemobj_flush**() for each range and then follow up by calling **pmemobj_drain**() once. For more information on partial flushing operations, see **pmem_flush**(3). # RETURN VALUE # The **pmemobj_memcpy_persist**() and **pmemobj_memset_persist**() functions return the same values as their namesakes **memcpy**(3), and **memset**(3). **pmemobj_persist**(), **pmemobj_flush**() and **pmemobj_drain**() return no value. # EXAMPLES # The following code is functionally equivalent to **pmemobj_memcpy_persist**(): ```c void * pmemobj_memcpy_persist(PMEMobjpool *pop, void *dest, const void *src, size_t len) { void *retval = memcpy(dest, src, len); pmemobj_persist(pop, dest, len); return retval; } ``` **pmemobj_persist**() can be thought of as this: ```c void pmemobj_persist(PMEMobjpool *pop, const void *addr, size_t len) { /* flush the processor caches */ pmemobj_flush(pop, addr, len); /* wait for any pmem stores to drain from HW buffers */ pmemobj_drain(pop); } ``` # SEE ALSO # **memcpy**(3), **memset**(3), **pmem_msync**(3), **pmem_persist**(3), **libpmem**(7) **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_mutex_zero.3.md000066400000000000000000000264311331545616200217460ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_MUTEX_ZERO, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_mutex_zero.3 -- man page for locking functions from libpmemobj library) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemobj_mutex_zero**(), **pmemobj_mutex_lock**(), **pmemobj_mutex_timedlock**(), **pmemobj_mutex_trylock**(), **pmemobj_mutex_unlock**(), **pmemobj_rwlock_zero**(), **pmemobj_rwlock_rdlock**(), **pmemobj_rwlock_wrlock**(), **pmemobj_rwlock_timedrdlock**(), **pmemobj_rwlock_timedwrlock**(), **pmemobj_rwlock_tryrdlock**(), **pmemobj_rwlock_trywrlock**(), **pmemobj_rwlock_unlock**(), **pmemobj_cond_zero**(), **pmemobj_cond_broadcast**(), **pmemobj_cond_signal**(), **pmemobj_cond_timedwait**(), **pmemobj_cond_wait**() -- pmemobj synchronization primitives # SYNOPSIS # ```c #include void pmemobj_mutex_zero(PMEMobjpool *pop, PMEMmutex *mutexp); int pmemobj_mutex_lock(PMEMobjpool *pop, PMEMmutex *mutexp); int pmemobj_mutex_timedlock(PMEMobjpool *pop, PMEMmutex *restrict mutexp, const struct timespec *restrict abs_timeout); int pmemobj_mutex_trylock(PMEMobjpool *pop, PMEMmutex *mutexp); int pmemobj_mutex_unlock(PMEMobjpool *pop, PMEMmutex *mutexp); void pmemobj_rwlock_zero(PMEMobjpool *pop, PMEMrwlock *rwlockp); int pmemobj_rwlock_rdlock(PMEMobjpool *pop, PMEMrwlock *rwlockp); int pmemobj_rwlock_wrlock(PMEMobjpool *pop, PMEMrwlock *rwlockp); int pmemobj_rwlock_timedrdlock(PMEMobjpool *pop, PMEMrwlock *restrict rwlockp, const struct timespec *restrict abs_timeout); int pmemobj_rwlock_timedwrlock(PMEMobjpool *pop, PMEMrwlock *restrict rwlockp, const struct timespec *restrict abs_timeout); int pmemobj_rwlock_tryrdlock(PMEMobjpool *pop, PMEMrwlock *rwlockp); int pmemobj_rwlock_trywrlock(PMEMobjpool *pop, PMEMrwlock *rwlockp); int pmemobj_rwlock_unlock(PMEMobjpool *pop, PMEMrwlock *rwlockp); void pmemobj_cond_zero(PMEMobjpool *pop, PMEMcond *condp); int pmemobj_cond_broadcast(PMEMobjpool *pop, PMEMcond *condp); int pmemobj_cond_signal(PMEMobjpool *pop, PMEMcond *condp); int pmemobj_cond_timedwait(PMEMobjpool *pop, PMEMcond *restrict condp, PMEMmutex *restrict mutexp, const struct timespec *restrict abs_timeout); int pmemobj_cond_wait(PMEMobjpool *pop, PMEMcond *restrict condp, PMEMmutex *restrict mutexp); ``` # DESCRIPTION # **libpmemobj**(7) provides several types of synchronization primitives designed to be used with persistent memory. The pmem-aware lock implementation is based on the standard POSIX Threads Library, as described in **pthread_mutex_init**(3), **pthread_rwlock_init**(3) and **pthread_cond_init**(3). Pmem-aware locks provide semantics similar to standard **pthread** locks, except that they are embedded in pmem-resident objects and are considered initialized by zeroing them. Therefore, locks allocated with **pmemobj_zalloc**(3) or **pmemobj_tx_zalloc**(3) do not require another initialization step. For performance reasons, they are also padded up to 64 bytes (cache line size). On FreeBSD, since all **pthread** locks are dynamically allocated, while the lock object is still padded up to 64 bytes for consistency with Linux, only the pointer to the lock is embedded in the pmem-resident object. **libpmemobj**(7) transparently manages freeing of the locks when the pool is closed. The fundamental property of pmem-aware locks is their automatic reinitialization every time the persistent object store pool is opened. Thus, all the pmem-aware locks may be considered initialized (unlocked) immediately after the pool is opened, regardless of their state at the time the pool was closed for the last time. Pmem-aware mutexes, read/write locks and condition variables must be declared with the *PMEMmutex*, *PMEMrwlock*, or *PMEMcond* type, respectively. The **pmemobj_mutex_zero**() function explicitly initializes the pmem-aware mutex *mutexp* by zeroing it. Initialization is not necessary if the object containing the mutex has been allocated using **pmemobj_zalloc**(3) or **pmemobj_tx_zalloc**(3). The **pmemobj_mutex_lock**() function locks the pmem-aware mutex *mutexp*. If the mutex is already locked, the calling thread will block until the mutex becomes available. If this is the first use of the mutex since the opening of the pool *pop*, the mutex is automatically reinitialized and then locked. **pmemobj_mutex_timedlock**() performs the same action as **pmemobj_mutex_lock**(), but will not wait beyond *abs_timeout* to obtain the lock before returning. The **pmemobj_mutex_trylock**() function locks pmem-aware mutex *mutexp*. If the mutex is already locked, **pthread_mutex_trylock**() will not block waiting for the mutex, but will return an error. If this is the first use of the mutex since the opening of the pool *pop*, the mutex is automatically reinitialized and then locked. The **pmemobj_mutex_unlock**() function unlocks the pmem-aware mutex *mutexp*. Undefined behavior follows if a thread tries to unlock a mutex that has not been locked by it, or if a thread tries to release a mutex that is already unlocked or has not been initialized. The **pmemobj_rwlock_zero**() function is used to explicitly initialize the pmem-aware read/write lock *rwlockp* by zeroing it. Initialization is not necessary if the object containing the lock has been allocated using **pmemobj_zalloc**(3) or **pmemobj_tx_zalloc**(3). The **pmemobj_rwlock_rdlock**() function acquires a read lock on *rwlockp*, provided that the lock is not presently held for writing and no writer threads are presently blocked on the lock. If the read lock cannot be acquired immediately, the calling thread blocks until it can acquire the lock. If this is the first use of the lock since the opening of the pool *pop*, the lock is automatically reinitialized and then acquired. **pmemobj_rwlock_timedrdlock**() performs the same action as **pmemobj_rwlock_rdlock**(), but will not wait beyond *abs_timeout* to obtain the lock before returning. A thread may hold multiple concurrent read locks. If so, **pmemobj_rwlock_unlock**() must be called once for each lock obtained. The results of acquiring a read lock while the calling thread holds a write lock are undefined. The **pmemobj_rwlock_wrlock**() function blocks until a write lock can be acquired against read/write lock *rwlockp*. If this is the first use of the lock since the opening of the pool *pop*, the lock is automatically reinitialized and then acquired. **pmemobj_rwlock_timedwrlock**() performs the same action, but will not wait beyond *abs_timeout* to obtain the lock before returning. The **pmemobj_rwlock_tryrdlock**() function performs the same action as **pmemobj_rwlock_rdlock**(), but does not block if the lock cannot be immediately obtained. The results are undefined if the calling thread already holds the lock at the time the call is made. The **pmemobj_rwlock_trywrlock**() function performs the same action as **pmemobj_rwlock_wrlock**(), but does not block if the lock cannot be immediately obtained. The results are undefined if the calling thread already holds the lock at the time the call is made. The **pmemobj_rwlock_unlock**() function is used to release the read/write lock previously obtained by **pmemobj_rwlock_rdlock**(), **pmemobj_rwlock_wrlock**(), **pthread_rwlock_tryrdlock**(), or **pmemobj_rwlock_trywrlock**(). The **pmemobj_cond_zero**() function explicitly initializes the pmem-aware condition variable *condp* by zeroing it. Initialization is not necessary if the object containing the condition variable has been allocated using **pmemobj_zalloc**(3) or **pmemobj_tx_zalloc**(3). The difference between **pmemobj_cond_broadcast**() and **pmemobj_cond_signal**() is that the former unblocks all threads waiting for the condition variable, whereas the latter blocks only one waiting thread. If no threads are waiting on *condp*, neither function has any effect. If more than one thread is blocked on a condition variable, the used scheduling policy determines the order in which threads are unblocked. The same mutex used for waiting must be held while calling either function. Although neither function strictly enforces this requirement, undefined behavior may follow if the mutex is not held. The **pmemobj_cond_timedwait**() and **pmemobj_cond_wait**() functions block on a condition variable. They must be called with mutex *mutexp* locked by the calling thread, or undefined behavior results. These functions atomically release mutex *mutexp* and cause the calling thread to block on the condition variable *condp*; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to **pmemobj_cond_broadcast**() or **pmemobj_cond_signal**() in that thread will behave as if it were issued after the about-to-block thread has blocked. Upon successful return, the mutex will be locked and owned by the calling thread. # RETURN VALUE # The **pmemobj_mutex_zero**(), **pmemobj_rwlock_zero**() and **pmemobj_cond_zero**() functions return no value. Other locking functions return 0 on success. Otherwise, an error number will be returned to indicate the error. # SEE ALSO # **pmemobj_tx_zalloc**(3), **pmemobj_zalloc**(3), **pthread_cond_init**(3), **pthread_mutex_init**(3), **pthread_rwlock_init**(3), **libpmem**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_open.3.md000066400000000000000000000214701331545616200205040ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_OPEN, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_open.3 -- man page for most commonly used functions from libpmemobj library) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[CAVEATS](#caveats)
[SEE ALSO](#see-also)
# NAME # _UW(pmemobj_open), _UW(pmemobj_create), **pmemobj_close**(), _UW(pmemobj_check) -- create, open, close and validate persistent memory transactional object store # SYNOPSIS # ```c #include _UWFUNCR1(PMEMobjpool, *pmemobj_open, *path, const char *layout) _UWFUNCR1(PMEMobjpool, *pmemobj_create, *path, =q=const char *layout, size_t poolsize, mode_t mode=e=) void pmemobj_close(PMEMobjpool *pop); _UWFUNCR1(int, pmemobj_check, *path, const char *layout) ``` _UNICODE() # DESCRIPTION # To use the pmem-resident transactional object store provided by **libpmemobj**(7), a *memory pool* must first be created with the _UW(pmemobj_create) function described below. Existing pools may be opened with the _UW(pmemobj_open) function. None of the three functions described below is thread-safe with respect to any other **libpmemobj**(7) functions. In other words, when creating, opening or deleting a pool, nothing else in the library can happen in parallel, and therefore these functions should be called from the main thread. Once created, the memory pool is represented by an opaque handle, of type *PMEMobjpool\**, which is passed to most of the other **libpmemobj**(7) functions. Internally, **libpmemobj**(7) will use either **pmem_persist**(3) or **msync**(2) when it needs to flush changes, depending on whether the memory pool appears to be persistent memory or a regular file (see the **pmem_is_pmem**(3) function in **libpmem**(7) for more information). There is no need for applications to flush changes directly when using the object memory API provided by **libpmemobj**(7). The _UW(pmemobj_create) function creates a transactional object store with the given total *poolsize*. *path* specifies the name of the memory pool file to be created. *layout* specifies the application's layout type in the form of a string. The layout name is not interpreted by **libpmemobj**(7), but may be used as a check when _UW(pmemobj_open) is called. The layout name, including the terminating null byte ('\0'), cannot be longer than **PMEMOBJ_MAX_LAYOUT** as defined in **\**. A NULL *layout* is equivalent to using an empty string as a layout name. *mode* specifies the permissions to use when creating the file, as described by **creat**(2). The memory pool file is fully allocated to the size *poolsize* using **posix_fallocate**(3). The caller may choose to take responsibility for creating the memory pool file by creating it before calling _UW(pmemobj_create), and then specifying *poolsize* as zero. In this case _UW(pmemobj_create) will take the pool size from the size of the existing file and will verify that the file appears to be empty by searching for any non-zero data in the pool header at the beginning of the file. The minimum net pool size allowed by the library for a local transactional object store is defined in **\** as **PMEMOBJ_MIN_POOL**. _WINUX(,=q=For remote replicas the minimum file size is defined in **\** as **RPMEM_MIN_PART**.=e=) Depending on the configuration of the system, the available non-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the pmemobj memory pool could be limited by the capacity of a single memory device. **libpmemobj**(7) allows building persistent memory resident object store spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a *pool set* may be stored on a different memory device or pmem-aware filesystem. Creation of all the parts of the pool set can be done with _UW(pmemobj_create); however, the recommended method for creating pool sets is with the **pmempool**(1) utility. When creating a pool set consisting of multiple files, the *path* argument passed to _UW(pmemobj_create) must point to the special *set* file that defines the pool layout and the location of all the parts of the pool set. The *poolsize* argument must be 0. The meaning of the *layout* and *mode* arguments does not change, except that the same *mode* is used for creation of all the parts of the pool set. The *set* file is a plain text file, the structure of which is described in **poolset**(5). The _UW(pmemobj_open) function opens an existing object store memory pool. Similar to _UW(pmemobj_create), *path* must identify either an existing obj memory pool file, or the *set* file used to create a pool set. If *layout* is non-NULL, it is compared to the layout name provided to _UW(pmemobj_create) when the pool was first created. This can be used to verify that the layout of the pool matches what was expected. The application must have permission to open the file and memory map it with read/write permissions. The **pmemobj_close**() function closes the memory pool indicated by *pop* and deletes the memory pool handle. The object store itself lives on in the file that contains it and may be re-opened at a later time using _UW(pmemobj_open) as described above. The _UW(pmemobj_check) function performs a consistency check of the file indicated by *path*. _UW(pmemobj_check) opens the given *path* read-only so it never makes any changes to the file. This function is not supported on Device DAX. # RETURN VALUE # The _UW(pmemobj_create) function returns a memory pool handle to be used with most of the functions in **libpmemobj**(7). On error it returns NULL and sets *errno* appropriately. The _UW(pmemobj_open) function returns a memory pool handle to be used with most of the functions in **libpmemobj**(7). If an error prevents the pool from being opened, or if the given *layout* does not match the pool's layout, _UW(pmemobj_open) returns NULL and sets *errno* appropriately. The **pmemobj_close**() function returns no value. The _UW(pmemobj_check) function returns 1 if the memory pool is found to be consistent. Any inconsistencies found will cause _UW(pmemobj_check) to return 0, in which case the use of the file with **libpmemobj**(7) will result in undefined behavior. The debug version of **libpmemobj**(7) will provide additional details on inconsistencies when **PMEMOBJ_LOG_LEVEL** is at least 1, asdescribed in the **DEBUGGING AND ERROR HANDLING** section in **libpmemobj**(7). _UW(pmemobj_check) returns -1 and sets *errno* if it cannot perform the consistency check due to other errors. # CAVEATS # Not all file systems support **posix_fallocate**(3). _UW(pmemobj_create) will fail if the underlying file system does not support **posix_fallocate**(3). # SEE ALSO # **creat**(2), **msync**(2), **pmem_is_pmem**(3), **pmem_persist**(3), **posix_fallocate**(3), **libpmem**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_root.3.md000066400000000000000000000130051331545616200205210ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_ROOT, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_root.3 -- man page for root object management) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemobj_root**(), **pmemobj_root_construct**() **POBJ_ROOT**(), **pmemobj_root_size**() -- root object management # SYNOPSIS # ```c #include PMEMoid pmemobj_root(PMEMobjpool *pop, size_t size); PMEMoid pmemobj_root_construct(PMEMobjpool *pop, size_t size, pmemobj_constr constructor, void *arg); POBJ_ROOT(PMEMobjpool *pop, TYPE) size_t pmemobj_root_size(PMEMobjpool *pop); ``` # DESCRIPTION # The root object of a persistent memory pool is an entry point for all other persistent objects allocated using the **libpmemobj** API. In other words, every object stored in the persistent memory pool has the root object at the end of its reference path. It may be assumed that for each persistent memory pool the root object always exists, and there is exactly one root object in each pool. The **pmemobj_root**() function creates or resizes the root object for the persistent memory pool *pop*. If this is the first call to **pmemobj_root**(), the requested *size* is greater than zero and the root object does not exist, it is implicitly allocated in a thread-safe manner, so the function may be called by more than one thread simultaneously (as long as all threads use the identical *size* value). The size of the root object is guaranteed to be not less than the requested *size*. If the requested size is larger than the current size, the root object is automatically resized. In such case, the old data is preserved and the extra space is zeroed. If the requested *size* is equal to zero, the root object is not allocated. **pmemobj_root_construct**() performs the same actions as **pmemobj_root**(), but instead of zeroing the newly allocated object a *constructor* function is called to initialize the object. The constructor is also called on reallocations. The **POBJ_ROOT**() macro works the same way as the **pmemobj_root**() function except it returns a typed *OID* value. The **pmemobj_root_size**() function returns the current size of the root object associated with the persistent memory pool *pop*. # RETURN VALUE # Upon success, **pmemobj_root**() returns a handle to the root object associated with the persistent memory pool *pop*. The same root object handle is returned in all the threads. If the requested object size is larger than the maximum allocation size supported for the pool, or if there is not enough free space in the pool to satisfy a reallocation request, **pmemobj_root**() returns **OID_NULL** and sets *errno* appropriately. If the *size* was equal to zero and the root object has not been allocated, **pmemobj_root**() returns **OID_NULL**. If the **pmemobj_root_construct**() constructor fails, the allocation is canceled, **pmemobj_root_construct**() returns *OID_NULL*, and *errno* is set to **ECANCELED**. **pmemobj_root_size**() can be used in the constructor to check whether this is the first call to the constructor. **POBJ_ROOT**() returns a typed *OID* of type *TYPE* instead of the *PMEMoid* returned by **pmemobj_root**(). The **pmemobj_root_size**() function returns the current size of the root object associated with the persistent memory pool *pop*. The returned size is the largest value requested by any of the earlier **pmemobj_root**() calls. If the root object has not been allocated yet, **pmemobj_root_size**() returns 0. # SEE ALSO # **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_tx_add_range.3.md000066400000000000000000000212331331545616200221570ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_TX_ADD_RANGE, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_tx_add_range.3 -- man page for transactional object manipulation) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemobj_tx_add_range**(), **pmemobj_tx_add_range_direct**(), **pmemobj_tx_xadd_range**(), **pmemobj_tx_xadd_range_direct**() **TX_ADD**(), **TX_ADD_FIELD**(), **TX_ADD_DIRECT**(), **TX_ADD_FIELD_DIRECT**(), **TX_XADD**(), **TX_XADD_FIELD**(), **TX_XADD_DIRECT**(), **TX_XADD_FIELD_DIRECT**(), **TX_SET**(), **TX_SET_DIRECT**(), **TX_MEMCPY**(), **TX_MEMSET**() -- transactional object manipulation # SYNOPSIS # ```c #include int pmemobj_tx_add_range(PMEMoid oid, uint64_t off, size_t size); int pmemobj_tx_add_range_direct(const void *ptr, size_t size); int pmemobj_tx_xadd_range(PMEMoid oid, uint64_t off, size_t size, uint64_t flags); int pmemobj_tx_xadd_range_direct(const void *ptr, size_t size, uint64_t flags); TX_ADD(TOID o) TX_ADD_FIELD(TOID o, FIELD) TX_ADD_DIRECT(TYPE *p) TX_ADD_FIELD_DIRECT(TYPE *p, FIELD) TX_XADD(TOID o, uint64_t flags) TX_XADD_FIELD(TOID o, FIELD, uint64_t flags) TX_XADD_DIRECT(TYPE *p, uint64_t flags) TX_XADD_FIELD_DIRECT(TYPE *p, FIELD, uint64_t flags) TX_SET(TOID o, FIELD, VALUE) TX_SET_DIRECT(TYPE *p, FIELD, VALUE) TX_MEMCPY(void *dest, const void *src, size_t num) TX_MEMSET(void *dest, int c, size_t num) ``` # DESCRIPTION # **pmemobj_tx_add_range**() takes a "snapshot" of the memory block of given *size*, located at given offset *off* in the object specified by *oid*, and saves it to the undo log. The application is then free to directly modify the object in that memory range. In case of a failure or abort, all the changes within this range will be rolled back. The supplied block of memory has to be within the pool registered in the transaction. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_xadd_range**() function behaves exactly the same as **pmemobj_tx_add_range**() when *flags* equals zero. *flags* is a bitmask of the following values: + **POBJ_XADD_NO_FLUSH** - skip flush on commit when application deals with flushing or uses pmemobj_memcpy_persist) **pmemobj_tx_add_range_direct**() behaves the same as **pmemobj_tx_add_range**() with the exception that it operates on virtual memory addresses and not persistent memory objects. It takes a "snapshot" of a persistent memory block of given *size*, located at the given address *ptr* in the virtual memory space and saves it to the undo log. The application is then free to directly modify the object in that memory range. In case of a failure or abort, all the changes within this range will be rolled back. The supplied block of memory has to be within the pool registered in the transaction. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_xadd_range_direct**() function behaves exactly the same as **pmemobj_tx_add_range_direct**() when *flags* equals zero. *flags* is a bitmask of the following values: + **POBJ_XADD_NO_FLUSH** - skip flush on commit (when application deals with flushing or uses pmemobj_memcpy_persist) Similarly to the macros controlling the transaction flow, **libpmemobj** defines a set of macros that simplify the transactional operations on persistent objects. Note that those macros operate on typed object handles, thus eliminating the need to specify the size of the object, or the size and offset of the field in the user-defined structure that is to be modified. The **TX_ADD_FIELD**() macro saves the current value of given *FIELD* of the object referenced by a handle *o* in the undo log. The application is then free to directly modify the specified *FIELD*. In case of a failure or abort, the saved value will be restored. The **TX_XADD_FIELD**() macro works exactly like **TX_ADD_FIELD** when *flags* equals 0. The *flags* argument is a bitmask of values described in **pmemobj_tx_xadd_range**, above. The **TX_ADD**() macro takes a "snapshot" of the entire object referenced by object handle *o* and saves it in the undo log. The object size is determined from its *TYPE*. The application is then free to directly modify the object. In case of a failure or abort, all the changes within the object will be rolled back. The **TX_XADD**() macro works exactly like **TX_ADD** when *flags* equals 0. The *flags* argument is a bitmask of values as described in **pmemobj_tx_xadd_range**, above. The **TX_ADD_FIELD_DIRECT**() macro saves the current value of the given *FIELD* of the object referenced by (direct) pointer *p* in the undo log. The application is then free to directly modify the specified *FIELD*. In case of a failure or abort, the saved value will be restored. The **TX_XADD_FIELD_DIRECT**() macro works exactly like **TX_ADD_FIELD_DIRECT** when *flags* equals 0. The *flags* argument is a bitmask of values as described in **pmemobj_tx_xadd_range_direct**, above. The **TX_ADD_DIRECT**() macro takes a "snapshot" of the entire object referenced by (direct) pointer *p* and saves it in the undo log. The object size is determined from its *TYPE*. The application is then free to directly modify the object. In case of a failure or abort, all the changes within the object will be rolled back. The **TX_XADD_DIRECT**() macro works exactly like **TX_ADD_DIRECT** when *flags* equals 0. The *flags* argument is a bitmask of values as described in **pmemobj_tx_xadd_range_direct**, above. The **TX_SET**() macro saves the current value of the given *FIELD* of the object referenced by handle *o* in the undo log, and then sets its new *VALUE*. In case of a failure or abort, the saved value will be restored. The **TX_SET_DIRECT**() macro saves in the undo log the current value of given *FIELD* of the object referenced by (direct) pointer *p*, and then set its new *VALUE*. In case of a failure or abort, the saved value will be restored. The **TX_MEMCPY**() macro saves in the undo log the current content of *dest* buffer and then overwrites the first *num* bytes of its memory area with the data copied from the buffer pointed by *src*. In case of a failure or abort, the saved value will be restored. The **TX_MEMSET**() macro saves the current content of the *dest* buffer in the undo log and then fills the first *num* bytes of its memory area with the constant byte *c*. In case of a failure or abort, the saved value will be restored. # RETURN VALUE # On success, **pmemobj_tx_add_range**(), **pmemobj_tx_xadd_range**(), **pmemobj_tx_add_range_direct**() and **pmemobj_tx_xadd_range_direct**() return 0. Otherwise, the stage is changed to **TX_STAGE_ONABORT** and an error number is returned. # SEE ALSO # **pmemobj_tx_alloc**(3), **pmemobj_tx_begin**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_tx_alloc.3.md000066400000000000000000000252631331545616200213540ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_TX_ALLOC, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_tx_alloc.3 -- man page for transactional object manipulation) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **pmemobj_tx_alloc**(), **pmemobj_tx_zalloc**(), **pmemobj_tx_xalloc**(), **pmemobj_tx_realloc**(), **pmemobj_tx_zrealloc**(), **pmemobj_tx_strdup**(), **pmemobj_tx_wcsdup**(), **pmemobj_tx_free**(), **TX_NEW**(), **TX_ALLOC**(), **TX_ZNEW**(), **TX_ZALLOC**(), **TX_XALLOC**(), **TX_REALLOC**(), **TX_ZREALLOC**(), **TX_STRDUP**(), **TX_WCSDUP**(), **TX_FREE**() -- transactional object manipulation # SYNOPSIS # ```c #include PMEMoid pmemobj_tx_alloc(size_t size, uint64_t type_num); PMEMoid pmemobj_tx_zalloc(size_t size, uint64_t type_num); PMEMoid pmemobj_tx_xalloc(size_t size, uint64_t type_num, uint64_t flags); PMEMoid pmemobj_tx_realloc(PMEMoid oid, size_t size, uint64_t type_num); PMEMoid pmemobj_tx_zrealloc(PMEMoid oid, size_t size, uint64_t type_num); PMEMoid pmemobj_tx_strdup(const char *s, uint64_t type_num); PMEMoid pmemobj_tx_wcsdup(const wchar_t *s, uint64_t type_num); int pmemobj_tx_free(PMEMoid oid); TX_NEW(TYPE) TX_ALLOC(TYPE, size_t size) TX_ZNEW(TYPE) TX_ZALLOC(TYPE, size_t size) TX_XALLOC(TYPE, size_t size, uint64_t flags) TX_REALLOC(TOID o, size_t size) TX_ZREALLOC(TOID o, size_t size) TX_STRDUP(const char *s, uint64_t type_num) TX_WCSDUP(const wchar_t *s, uint64_t type_num) TX_FREE(TOID o) ``` # DESCRIPTION # The **pmemobj_tx_alloc**() function transactionally allocates a new object of given *size* and *type_num*. In contrast to the non-transactional allocations, the objects are added to the internal object containers of given *type_num* only after the transaction is committed, making the objects visible to the **POBJ_FOREACH_\***() macros. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_zalloc**() function transactionally allocates a new zeroed object of given *size* and *type_num*. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_xalloc**() function transactionally allocates a new object of given *size* and *type_num*. The *flags* argument is a bitmask of the following values: + **POBJ_XALLOC_ZERO** - zero the object (equivalent of pmemobj_tx_zalloc) + **POBJ_XALLOC_NO_FLUSH** - skip flush on commit (when application deals with flushing or uses pmemobj_memcpy_persist) + **POBJ_CLASS_ID(class_id)** - allocate the object from the allocation class with id equal to *class_id* This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_realloc**() function transactionally resizes an existing object to the given *size* and changes its type to *type_num*. If *oid* is **OID_NULL**, then the call is equivalent to *pmemobj_tx_alloc(pop, size, type_num)*. If *size* is equal to zero and *oid* is not **OID_NULL**, then the call is equivalent to *pmemobj_tx_free(oid)*. If the new size is larger than the old size, the added memory will *not* be initialized. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_zrealloc**() function transactionally resizes an existing object to the given *size* and changes its type to *type_num*. If the new size is larger than the old size, the extended new space is zeroed. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_strdup**() function transactionally allocates a new object containing a duplicate of the string *s* and assigns it a type *type_num*. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_wcsdup**() function transactionally allocates a new object containing a duplicate of the wide character string *s* and assigns it a type *type_num*. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_free**() function transactionally frees an existing object referenced by *oid*. This function must be called during **TX_STAGE_WORK**. The **TX_NEW**() macro transactionally allocates a new object of given *TYPE* and assigns it a type number read from the typed *OID*. The allocation size is determined from the size of the user-defined structure *TYPE*. If successful and called during **TX_STAGE_WORK** it returns a handle to the newly allocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_ALLOC**() macro transactionally allocates a new object of given *TYPE* and assigns it a type number read from the typed *OID*. The allocation size is passed by *size* parameter. If successful and called during **TX_STAGE_WORK** it returns a handle to the newly allocated object. Otherwise, the stage is set to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_ZNEW**() macro transactionally allocates a new zeroed object of given *TYPE* and assigns it a type number read from the typed *OID*. The allocation size is determined from the size of the user-defined structure *TYPE*. If successful and called during **TX_STAGE_WORK** it returns a handle to the newly allocated object. Otherwise, stage changes to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_ZALLOC**() macro transactionally allocates a new zeroed object of given *TYPE* and assigns it a type number read from the typed *OID*. The allocation size is passed by *size* argument. If successful and called during **TX_STAGE_WORK** it returns a handle to the newly allocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_XALLOC**() macro transactionally allocates a new object of given *TYPE* and assigns it a type number read from the typed *OID*. The allocation size is passed by *size* argument. The *flags* argument is a bitmask of values described in **pmemobj_tx_xalloc** section. If successful and called during **TX_STAGE_WORK** it returns a handle to the newly allocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_REALLOC**() macro transactionally resizes an existing object referenced by a handle *o* to the given *size*. If successful and called during **TX_STAGE_WORK** it returns a handle to the reallocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_ZREALLOC**() macro transactionally resizes an existing object referenced by a handle *o* to the given *size*. If the new size is larger than the old size, the extended new space is zeroed. If successful and called during **TX_STAGE_WORK** it returns a handle to the reallocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_STRDUP**() macro transactionally allocates a new object containing a duplicate of the string *s* and assigns it type *type_num*. If successful and called during **TX_STAGE_WORK** it returns a handle to the newly allocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_WCSDUP**() macro transactionally allocates a new object containing a duplicate of the wide character string *s* and assigns it a type *type_num*. If successful and called during **TX_STAGE_WORK**, it returns a handle to the newly allocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. The **TX_FREE**() macro transactionally frees the memory space represented by an object handle *o*. If *o* is **OID_NULL**, no operation is performed. If successful and called during **TX_STAGE_WORK**, **TX_FREE**() returns 0. Otherwise, the stage is changed to **TX_STAGE_ONABORT** and an error number is returned. # RETURN VALUE # On success, the **pmemobj_tx_alloc**() ,**pmemobj_tx_zalloc**(), **pmemobj_tx_xalloc**(), **pmemobj_tx_strdup**() and **pmemobj_tx_wcsdup**() functions return a handle to the newly allocated object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. If *size* equals 0, **OID_NULL** is returned and *errno* is set appropriately. On success, **pmemobj_tx_realloc**() and **pmemobj_tx_zrealloc**() return a handle to the resized object. Otherwise, the stage is changed to **TX_STAGE_ONABORT**, **OID_NULL** is returned, and *errno* is set appropriately. Note that the object handle value may change as a result of reallocation. On success, **pmemobj_tx_free**() returns 0. Otherwise, the stage is set to **TX_STAGE_ONABORT** and an error number is returned. # SEE ALSO # **pmemobj_tx_add_range**(3), **pmemobj_tx_begin*(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pmemobj_tx_begin.3.md000066400000000000000000000432161331545616200213440ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMOBJ_TX_BEGIN, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmemobj_tx_begin.3 -- man page for transactional object manipulation) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[CAVEATS](#caveats)
[SEE ALSO](#see-also)
# NAME # **pmemobj_tx_stage**(), **pmemobj_tx_begin**(), **pmemobj_tx_lock**(), **pmemobj_tx_abort**(), **pmemobj_tx_commit**(), **pmemobj_tx_end**(), **pmemobj_tx_errno**(), **pmemobj_tx_process**(), **TX_BEGIN_PARAM**(), **TX_BEGIN_CB**(), **TX_BEGIN**(), **TX_ONABORT**, **TX_ONCOMMIT**, **TX_FINALLY**, **TX_END** -- transactional object manipulation # SYNOPSIS # ```c #include enum tx_stage pmemobj_tx_stage(void); int pmemobj_tx_begin(PMEMobjpool *pop, jmp_buf *env, enum pobj_tx_param, ...); int pmemobj_tx_lock(enum tx_lock lock_type, void *lockp); void pmemobj_tx_abort(int errnum); void pmemobj_tx_commit(void); int pmemobj_tx_end(void); int pmemobj_tx_errno(void); void pmemobj_tx_process(void); TX_BEGIN_PARAM(PMEMobjpool *pop, ...) TX_BEGIN_CB(PMEMobjpool *pop, cb, arg, ...) TX_BEGIN(PMEMobjpool *pop) TX_ONABORT TX_ONCOMMIT TX_FINALLY TX_END ``` # DESCRIPTION # The non-transactional functions and macros described in **pmemobj_alloc**(3), **pmemobj_list_insert**(3) and **POBJ_LIST_HEAD**(3) only guarantee the atomicity of a single operation on an object. In case of more complex changes involving multiple operations on an object, or allocation and modification of multiple objects, data consistency and fail-safety may be provided only by using *atomic transactions*. A transaction is defined as series of operations on persistent memory objects that either all occur, or nothing occurs. In particular, if the execution of a transaction is interrupted by a power failure or a system crash, it is guaranteed that after system restart, all the changes made as a part of the uncompleted transaction will be rolled back, restoring the consistent state of the memory pool from the moment when the transaction was started. Note that transactions do not provide atomicity with respect to other threads. All the modifications performed within the transactions are immediately visible to other threads. Therefore it is the responsibility of the application to implement a proper thread synchronization mechanism. Each thread may have only one transaction open at a time, but that transaction may be nested. Nested transactions are flattened. Committing the nested transaction does not commit the outer transaction; however, errors in the nested transaction are propagated up to the outermost level, resulting in the interruption of the entire transaction. Each transaction is visible only for the thread that started it. No other threads can add operations, commit or abort the transaction initiated by another thread. Multiple threads may have transactions open on a given memory pool at the same time. Please see the **CAVEATS** section below for known limitations of the transactional API. The **pmemobj_tx_stage**() function returns the current *transaction stage* for a thread. Stages are changed only by the **pmemobj_tx_\***() functions. Transaction stages are defined as follows: + **TX_STAGE_NONE** - no open transaction in this thread + **TX_STAGE_WORK** - transaction in progress + **TX_STAGE_ONCOMMIT** - successfully committed + **TX_STAGE_ONABORT** - starting the transaction failed or transaction aborted + **TX_STAGE_FINALLY** - ready for clean up The **pmemobj_tx_begin**() function starts a new transaction in the current thread. If called within an open transaction, it starts a nested transaction. The caller may use the *env* argument to provide a pointer to a calling environment to be restored in case of transaction abort. This information must be provided by the caller using the **setjmp**(3) macro. A new transaction may be started only if the current stage is **TX_STAGE_NONE** or **TX_STAGE_WORK**. If successful, the *transaction stage* changes to **TX_STAGE_WORK**. Otherwise, the stage is changed to **TX_STAGE_ONABORT**. Optionally, a list of parameters for the transaction may be provided. Each parameter consists of a type followed by a type-specific number of values. Currently there are 4 types: + **TX_PARAM_NONE**, used as a termination marker. No following value. + **TX_PARAM_MUTEX**, followed by one value, a pmem-resident PMEMmutex + **TX_PARAM_RWLOCK**, followed by one value, a pmem-resident PMEMrwlock + **TX_PARAM_CB**, followed by two values: a callback function of type *pmemobj_tx_callback*, and a void pointer Using **TX_PARAM_MUTEX** or **TX_PARAM_RWLOCK** causes the specified lock to be acquired at the beginning of the transaction. **TX_PARAM_RWLOCK** acquires the lock for writing. It is guaranteed that **pmemobj_tx_begin**() will acquire all locks prior to successful completion, and they will be held by the current thread until the outermost transaction is finished. Locks are taken in order from left to right. To avoid deadlocks, the user is responsible for proper lock ordering. **TX_PARAM_CB** registers the specified callback function to be executed at each transaction stage. For **TX_STAGE_WORK**, the callback is executed prior to commit. For all other stages, the callback is executed as the first operation after a stage change. It will also be called after each transaction; in this case the *stage* parameter will be set to **TX_STAGE_NONE**. *pmemobj_tx_callback* must be compatible with: ```void func(PMEMobjpool *pop, enum pobj_tx_stage stage, void *arg)``` *pop* is a pool identifier used in **pmemobj_tx_begin**(), *stage* is a current transaction stage and *arg* is the second parameter of **TX_PARAM_CB**. Without considering transaction nesting, this mechanism can be considered an alternative method for executing code between stages (instead of **TX_ONCOMMIT**, **TX_ONABORT**, etc). However, there are 2 significant differences when nested transactions are used: + The registered function is executed only in the outermost transaction, even if registered in an inner transaction. + There can be only one callback in the entire transaction, that is, the callback cannot be changed in an inner transaction. Note that **TX_PARAM_CB** does not replace the **TX_ONCOMMIT**, **TX_ONABORT**, etc. macros. They can be used together: the callback will be executed *before* a **TX_ONCOMMIT**, **TX_ONABORT**, etc. section. **TX_PARAM_CB** can be used when the code dealing with transaction stage changes is shared between multiple users or when it must be executed only in the outer transaction. For example it can be very useful when the application must synchronize persistent and transient state. The **pmemobj_tx_lock**() function acquires the lock *lockp* of type *lock_type* and adds it to the current transaction. *lock_type* may be **TX_LOCK_MUTEX** or **TX_LOCK_RWLOCK**; *lockp* must be of type *PMEMmutex* or *PMEMrwlock*, respectively. If *lock_type* is **TX_LOCK_RWLOCK** the lock is acquired for writing. If the lock is not successfully acquired, the stage is changed to **TX_STAGE_ONABORT**. This function must be called during **TX_STAGE_WORK**. **pmemobj_tx_abort**() aborts the current transaction and causes a transition to **TX_STAGE_ONABORT**. If *errnum* is equal to 0, the transaction error code is set to **ECANCELED**; otherwise, it is set to *errnum*. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_commit**() function commits the current open transaction and causes a transition to **TX_STAGE_ONCOMMIT**. If called in the context of the outermost transaction, all the changes may be considered as durably written upon successful completion. This function must be called during **TX_STAGE_WORK**. The **pmemobj_tx_end**() function performs a cleanup of the current transaction. If called in the context of the outermost transaction, it releases all the locks acquired by **pmemobj_tx_begin**() for outer and nested transactions. If called in the context of a nested transaction, it returns to the context of the outer transaction in **TX_STAGE_WORK**, without releasing any locks. The **pmemobj_tx_end**() function can be called during **TX_STAGE_NONE** if transitioned to this stage using **pmemobj_tx_process**(). If not already in **TX_STAGE_NONE**, it causes the transition to **TX_STAGE_NONE**. **pmemobj_tx_end** must always be called for each **pmemobj_tx_begin**(), even if starting the transaction failed. This function must *not* be called during **TX_STAGE_WORK**. The **pmemobj_tx_errno**() function returns the error code of the last transaction. The **pmemobj_tx_process**() function performs the actions associated with the current stage of the transaction, and makes the transition to the next stage. It must be called in a transaction. The current stage must always be obtained by a call to **pmemobj_tx_stage**(). **pmemobj_tx_process**() performs the following transitions in the transaction stage flow: + **TX_STAGE_WORK** -> **TX_STAGE_ONCOMMIT** + **TX_STAGE_ONABORT** -> **TX_STAGE_FINALLY** + **TX_STAGE_ONCOMMIT** -> **TX_STAGE_FINALLY** + **TX_STAGE_FINALLY** -> **TX_STAGE_NONE** + **TX_STAGE_NONE** -> **TX_STAGE_NONE** **pmemobj_tx_process**() must not be called after calling **pmemobj_tx_end**() for the outermost transaction. In addition to the above API, **libpmemobj**(7) offers a more intuitive method of building transactions using the set of macros described below. When using these macros, the complete transaction flow looks like this: ```c TX_BEGIN(Pop) { /* the actual transaction code goes here... */ } TX_ONCOMMIT { /* * optional - executed only if the above block * successfully completes */ } TX_ONABORT { /* * optional - executed only if starting the transaction fails, * or if transaction is aborted by an error or a call to * pmemobj_tx_abort() */ } TX_FINALLY { /* * optional - if exists, it is executed after * TX_ONCOMMIT or TX_ONABORT block */ } TX_END /* mandatory */ ``` ```c TX_BEGIN_PARAM(PMEMobjpool *pop, ...) TX_BEGIN_CB(PMEMobjpool *pop, cb, arg, ...) TX_BEGIN(PMEMobjpool *pop) ``` The **TX_BEGIN_PARAM**(), **TX_BEGIN_CB**() and **TX_BEGIN**() macros start a new transaction in the same way as **pmemobj_tx_begin**(), except that instead of the environment buffer provided by a caller, they set up the local *jmp_buf* buffer and use it to catch the transaction abort. The **TX_BEGIN**() macro starts a transaction without any options. **TX_BEGIN_PARAM** may be used when there is a need to acquire locks prior to starting a transaction (such as for a multi-threaded program) or set up a transaction stage callback. **TX_BEGIN_CB** is just a wrapper around **TX_BEGIN_PARAM** that validates the callback signature. (For compatibility there is also a **TX_BEGIN_LOCK** macro, which is an alias for **TX_BEGIN_PARAM**). Each of these macros must be followed by a block of code with all the operations that are to be performed atomically. The **TX_ONABORT** macro starts a block of code that will be executed only if starting the transaction fails due to an error in **pmemobj_tx_begin**(), or if the transaction is aborted. This block is optional, but in practice it should not be omitted. If it is desirable to crash the application when a transaction aborts and there is no **TX_ONABORT** section, the application can define the **POBJ_TX_CRASH_ON_NO_ONABORT** macro before inclusion of **\**. This provides a default **TX_ONABORT** section which just calls **abort**(3). The **TX_ONCOMMIT** macro starts a block of code that will be executed only if the transaction is successfully committed, which means that the execution of code in the **TX_BEGIN**() block has not been interrupted by an error or by a call to **pmemobj_tx_abort**(). This block is optional. The **TX_FINALLY** macro starts a block of code that will be executed regardless of whether the transaction is committed or aborted. This block is optional. The **TX_END** macro cleans up and closes the transaction started by the **TX_BEGIN**() / **TX_BEGIN_PARAM**() / **TX_BEGIN_CB**() macros. It is mandatory to terminate each transaction with this macro. If the transaction was aborted, *errno* is set appropriately. # RETURN VALUE # The **pmemobj_tx_stage**() function returns the stage of the current transaction stage for a thread. On success, **pmemobj_tx_begin**() returns 0. Otherwise, an error number is returned. The **pmemobj_tx_begin**() and **pmemobj_tx_lock**() functions return zero if *lockp* is successfully added to the transaction. Otherwise, an error number is returned. The **pmemobj_tx_abort**() and **pmemobj_tx_commit**() functions return no value. The **pmemobj_tx_end**() function returns 0 if the transaction was successful. Otherwise it returns the error code set by **pmemobj_tx_abort**(). Note that **pmemobj_tx_abort**() can be called internally by the library. The **pmemobj_tx_errno**() function returns the error code of the last transaction. The **pmemobj_tx_process**() function returns no value. # CAVEATS # Transaction flow control is governed by the **setjmp**(3) and **longjmp**(3) macros, and they are used in both the macro and function flavors of the API. The transaction will longjmp on transaction abort. This has one major drawback, which is described in the ISO C standard subsection 7.13.2.1. It says that **the values of objects of automatic storage duration that are local to the function containing the setjmp invocation that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate.** The following example illustrates the issue described above. ```c int *bad_example_1 = (int *)0xBAADF00D; int *bad_example_2 = (int *)0xBAADF00D; int *bad_example_3 = (int *)0xBAADF00D; int * volatile good_example = (int *)0xBAADF00D; TX_BEGIN(pop) { bad_example_1 = malloc(sizeof(int)); bad_example_2 = malloc(sizeof(int)); bad_example_3 = malloc(sizeof(int)); good_example = malloc(sizeof(int)); /* manual or library abort called here */ pmemobj_tx_abort(EINVAL); } TX_ONCOMMIT { /* * This section is longjmp-safe */ } TX_ONABORT { /* * This section is not longjmp-safe */ free(good_example); /* OK */ free(bad_example_1); /* undefined behavior */ } TX_FINALLY { /* * This section is not longjmp-safe on transaction abort only */ free(bad_example_2); /* undefined behavior */ } TX_END free(bad_example_3); /* undefined behavior */ ``` Objects which are not volatile-qualified, are of automatic storage duration and have been changed between the invocations of **setjmp**(3) and **longjmp**(3) (that also means within the work section of the transaction after **TX_BEGIN**()) should not be used after a transaction abort, or should be used with utmost care. This also includes code after the **TX_END** macro. **libpmemobj**(7) is not cancellation-safe. The pool will never be corrupted because of a canceled thread, but other threads may stall waiting on locks taken by that thread. If the application wants to use **pthread_cancel**(3), it must disable cancellation before calling any **libpmemobj**(7) APIs (see **pthread_setcancelstate**(3) with **PTHREAD_CANCEL_DISABLE**), and re-enable it afterwards. Deferring cancellation (**pthread_setcanceltype**(3) with **PTHREAD_CANCEL_DEFERRED**) is not safe enough, because **libpmemobj**(7) internally may call functions that are specified as cancellation points in POSIX. **libpmemobj**(7) relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # SEE ALSO # **dlclose**(3), **longjmp**(3), **pmemobj_tx_add_range**(3), **pmemobj_tx_alloc**(3), **pthread_setcancelstate**(3), **pthread_setcanceltype**(3), **setjmp**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pobj_layout_begin.3.md000066400000000000000000000116371331545616200215310ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(POBJ_LAYOUT_BEGIN, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pobj_layout_begin.3 -- man page for declaration of pool's layout) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **POBJ_LAYOUT_BEGIN**(), **POBJ_LAYOUT_TOID**(), **POBJ_LAYOUT_ROOT**(), **POBJ_LAYOUT_NAME**(), **POBJ_LAYOUT_END**(), **POBJ_LAYOUT_TYPES_NUM**() -- persistent memory transactional object store layout # SYNOPSIS # ```c #include POBJ_LAYOUT_BEGIN(layout) POBJ_LAYOUT_TOID(layout, TYPE) POBJ_LAYOUT_ROOT(layout, ROOT_TYPE) POBJ_LAYOUT_NAME(layout) POBJ_LAYOUT_END(layout) POBJ_LAYOUT_TYPES_NUM(layout) ``` # DESCRIPTION # **libpmemobj**(7) defines a set of macros for convenient declaration of a pool's layout. The layout declaration consists of declarations of a number of used types. The declared types will be assigned consecutive type numbers. Declared types may be used in conjunction with type safety macros (see **TOID_DECLARE**(3)). Once created, the layout declaration must not be changed unless any new types are added at the end of the existing layout declaration. Modifying any existing declaration may lead to changes in the type numbers of declared types, which in consequence may cause data corruption. The **POBJ_LAYOUT_BEGIN**() macro indicates a begin of declaration of layout. The *LAYOUT* argument is a name of layout. This argument must be passed to all macros related to the declaration of layout. The **POBJ_LAYOUT_TOID**() macro declares a typed *OID* for type passed as *TYPE* argument inside the declaration of layout. All types declared using this macro are assigned with consecutive type numbers. This macro must be used between the **POBJ_LAYOUT_BEGIN**() and **POBJ_LAYOUT_END**() macros, with the same name passed as *LAYOUT* argument. The **POBJ_LAYOUT_ROOT**() macro declares a typed *OID* for type passed as *ROOT_TYPE* argument inside the declaration of layout. The typed *OID* will be assigned with type number for root object **POBJ_ROOT_TYPE_NUM**. The **POBJ_LAYOUT_END**() macro ends the declaration of layout. The **POBJ_LAYOUT_NAME**() macro returns the name of layout as a null-terminated string. The **POBJ_LAYOUT_TYPES_NUM**() macro returns number of types declared using the **POBJ_LAYOUT_TOID**() macro within the layout declaration. # EXAMPLE # This is an example of layout declaration: ```c POBJ_LAYOUT_BEGIN(mylayout); POBJ_LAYOUT_ROOT(mylayout, struct root); POBJ_LAYOUT_TOID(mylayout, struct node); POBJ_LAYOUT_TOID(mylayout, struct foo); POBJ_LAYOUT_END(mylayout); struct root { TOID(struct node) node; }; struct node { TOID(struct node) next; TOID(struct foo) foo; }; ``` The name of layout and the number of declared types can be retrieved using the following code: ```c const char *layout_name = POBJ_LAYOUT_NAME(mylayout); int num_of_types = POBJ_LAYOUT_TYPES_NUM(mylayout); ``` # SEE ALSO # **TOID_DECLARE**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/pobj_list_head.3.md000066400000000000000000000276441331545616200210110ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(POBJ_LIST_HEAD, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pobj_list_head.3 -- man page for type-safe non-transactional persistent atomic lists) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[SEE ALSO](#see-also)
# NAME # **POBJ_LIST_HEAD**(), **POBJ_LIST_ENTRY**(), **POBJ_LIST_FIRST**(), **POBJ_LIST_LAST**(), **POBJ_LIST_EMPTY**(), **POBJ_LIST_NEXT**(), **POBJ_LIST_PREV**(), **POBJ_LIST_FOREACH**(), **POBJ_LIST_FOREACH_REVERSE**(), **POBJ_LIST_INSERT_HEAD**(), **POBJ_LIST_INSERT_TAIL**(), **POBJ_LIST_INSERT_AFTER**(), **POBJ_LIST_INSERT_BEFORE**(), **POBJ_LIST_INSERT_NEW_HEAD**(), **POBJ_LIST_INSERT_NEW_TAIL**(), **POBJ_LIST_INSERT_NEW_AFTER**(), **POBJ_LIST_INSERT_NEW_BEFORE**(), **POBJ_LIST_REMOVE**(), **POBJ_LIST_REMOVE_FREE**(), **POBJ_LIST_MOVE_ELEMENT_HEAD**(), **POBJ_LIST_MOVE_ELEMENT_TAIL**(), **POBJ_LIST_MOVE_ELEMENT_AFTER**(), **POBJ_LIST_MOVE_ELEMENT_BEFORE**() -- type-safe non-transactional persistent atomic lists # SYNOPSIS # ```c #include POBJ_LIST_HEAD(HEADNAME, TYPE) POBJ_LIST_ENTRY(TYPE) POBJ_LIST_FIRST(POBJ_LIST_HEAD *head) POBJ_LIST_LAST(POBJ_LIST_HEAD *head, POBJ_LIST_ENTRY FIELD) POBJ_LIST_EMPTY(POBJ_LIST_HEAD *head) POBJ_LIST_NEXT(TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_PREV(TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_FOREACH(TOID var, POBJ_LIST_HEAD *head, POBJ_LIST_ENTRY FIELD) POBJ_LIST_FOREACH_REVERSE(TOID var, POBJ_LIST_HEAD *head, POBJ_LIST_ENTRY FIELD) POBJ_LIST_INSERT_HEAD(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_INSERT_TAIL(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_INSERT_AFTER(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID listelm, TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_INSERT_BEFORE(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID listelm, TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_INSERT_NEW_HEAD(PMEMobjpool *pop, POBJ_LIST_HEAD *head, POBJ_LIST_ENTRY FIELD, size_t size, pmemobj_constr constructor, void *arg) POBJ_LIST_INSERT_NEW_TAIL(PMEMobjpool *pop, POBJ_LIST_HEAD *head, POBJ_LIST_ENTRY FIELD, size_t size, pmemobj_constr constructor, void *arg) POBJ_LIST_INSERT_NEW_AFTER(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID listelm, POBJ_LIST_ENTRY FIELD, size_t size, pmemobj_constr constructor, void *arg) POBJ_LIST_INSERT_NEW_BEFORE(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID listelm, POBJ_LIST_ENTRY FIELD, size_t size, pmemobj_constr constructor, void *arg) POBJ_LIST_REMOVE(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_REMOVE_FREE(PMEMobjpool *pop, POBJ_LIST_HEAD *head, TOID elm, POBJ_LIST_ENTRY FIELD) POBJ_LIST_MOVE_ELEMENT_HEAD(PMEMobjpool *pop, POBJ_LIST_HEAD *head, POBJ_LIST_HEAD *head_new, TOID elm, POBJ_LIST_ENTRY FIELD, POBJ_LIST_ENTRY field_new) POBJ_LIST_MOVE_ELEMENT_TAIL(PMEMobjpool *pop, POBJ_LIST_HEAD *head, POBJ_LIST_HEAD *head_new, TOID elm, POBJ_LIST_ENTRY FIELD, POBJ_LIST_ENTRY field_new) POBJ_LIST_MOVE_ELEMENT_AFTER(PMEMobjpool *pop, POBJ_LIST_HEAD *head, POBJ_LIST_HEAD *head_new, TOID listelm, TOID elm, POBJ_LIST_ENTRY FIELD, POBJ_LIST_ENTRY field_new) POBJ_LIST_MOVE_ELEMENT_BEFORE(PMEMobjpool *pop, POBJ_LIST_HEAD *head, POBJ_LIST_HEAD *head_new, TOID listelm, TOID elm, POBJ_LIST_ENTRY FIELD, POBJ_LIST_ENTRY field_new) ``` # DESCRIPTION # The following macros define and operate on a type-safe persistent atomic circular doubly linked list data structure that consist of a set of persistent objects of a well-known type. Unlike the functions described in the previous section, these macros provide type enforcement by requiring declaration of type of the objects stored in given list, and not allowing mixing objects of different types in a single list. The functionality and semantics of those macros is similar to circular queues defined in **queue**(3). The majority of the macros must specify the handle to the memory pool *pop* and the name of the *field* in the user-defined structure, which must be of type *POBJ_LIST_ENTRY* and is used to connect the elements in the list. A list is headed by a structure defined by the **POBJ_LIST_HEAD**() macro. This structure contains an object handle of the first element on the list. The elements are doubly linked so that an arbitrary element can be removed without a need to traverse the list. New elements can be added to the list before or after an existing element, at the head of the list, or at the end of the list. A list may be traversed in either direction. A *POBJ_LIST_HEAD* structure is declared as follows: ```c #define POBJ_LIST_HEAD(HEADNAME, TYPE) struct HEADNAME { TOID(TYPE) pe_first; PMEMmutex lock; }; ``` In the macro definitions, *TYPE* is the name of a user-defined structure, that must contain a field of type *POBJ_LIST_ENTRY*. The argument *HEADNAME* is the name of a user-defined structure that must be declared using the macro *POBJ_LIST_HEAD*. See the examples below for further explanation of how these macros are used. The macro *POBJ_LIST_ENTRY* declares a structure that connects the elements in the list. ```c #define POBJ_LIST_ENTRY(TYPE) struct { TOID(TYPE) pe_next; TOID(TYPE) pe_prev; }; ``` The macro **POBJ_LIST_FIRST**() returns the first element on the list referenced by *head*. If the list is empty **OID_NULL** is returned. The macro **POBJ_LIST_LAST**() returns the last element on the list referenced by *head*. If the list is empty **OID_NULL** is returned. The macro **POBJ_LIST_EMPTY**() evaluates to 1 if the list referenced by *head* is empty. Otherwise, 0 is returned. The macro **POBJ_LIST_NEXT**() returns the element next to the element *elm*. The macro **POBJ_LIST_PREV**() returns the element preceding the element *elm*. The macro **POBJ_LIST_FOREACH**() traverses the list referenced by *head* assigning a handle to each element in turn to *var* variable. The macro **POBJ_LIST_FOREACH_REVERSE**() traverses the list referenced by *head* in reverse order, assigning a handle to each element in turn to *var* variable. The *field* argument is the name of the field of type *POBJ_LIST_ENTRY* in the element structure. The macro **POBJ_LIST_INSERT_HEAD**() inserts the element *elm* at the head of the list referenced by *head*. The macro **POBJ_LIST_INSERT_TAIL**() inserts the element *elm* at the end of the list referenced by *head*. The macro **POBJ_LIST_INSERT_AFTER**() inserts the element *elm* into the list referenced by *head* after the element *listelm*. If *listelm* value is **TOID_NULL**, the object is inserted at the end of the list. The macro **POBJ_LIST_INSERT_BEFORE**() inserts the element *elm* into the list referenced by *head* before the element *listelm*. If *listelm* value is **TOID_NULL**, the object is inserted at the head of the list. The macro **POBJ_LIST_INSERT_NEW_HEAD**() atomically allocates a new object of size *size* and inserts it at the head of the list referenced by *head*. The newly allocated object is also added to the internal object container associated with a type number which is retrieved from the typed *OID* of the first element on list. The macro **POBJ_LIST_INSERT_NEW_TAIL**() atomically allocates a new object of size *size* and inserts it at the tail of the list referenced by *head*. The newly allocated object is also added to the internal object container associated with with a type number which is retrieved from the typed *OID* of the first element on list. The macro **POBJ_LIST_INSERT_NEW_AFTER**() atomically allocates a new object of size *size* and inserts it into the list referenced by *head* after the element *listelm*. If *listelm* value is **TOID_NULL**, the object is inserted at the end of the list. The newly allocated object is also added to the internal object container associated with with a type number which is retrieved from the typed *OID* of the first element on list. The macro **POBJ_LIST_INSERT_NEW_BEFORE**() atomically allocates a new object of size *size* and inserts it into the list referenced by *head* before the element *listelm*. If *listelm* value is **TOID_NULL**, the object is inserted at the head of the list. The newly allocated object is also added to the internal object container associated with with a type number which is retrieved from the typed *OID* of the first element on list. The macro **POBJ_LIST_REMOVE**() removes the element *elm* from the list referenced by *head*. The macro **POBJ_LIST_REMOVE_FREE**() removes the element *elm* from the list referenced by *head* and frees the memory space represented by this element. The macro **POBJ_LIST_MOVE_ELEMENT_HEAD**() moves the element *elm* from the list referenced by *head* to the head of the list *head_new*. The *field* and *field_new* arguments are the names of the fields of type *POBJ_LIST_ENTRY* in the element structure that are used to connect the elements in both lists. The macro **POBJ_LIST_MOVE_ELEMENT_TAIL**() moves the element *elm* from the list referenced by *head* to the end of the list *head_new*. The *field* and *field_new* arguments are the names of the fields of type *POBJ_LIST_ENTRY* in the element structure that are used to connect the elements in both lists. The macro **POBJ_LIST_MOVE_ELEMENT_AFTER**() atomically removes the element *elm* from the list referenced by *head* and inserts it into the list referenced by *head_new* after the element *listelm*. If *listelm* value is *TOID_NULL*, the object is inserted at the end of the list. The *field* and *field_new* arguments are the names of the fields of type *POBJ_LIST_ENTRY* in the element structure that are used to connect the elements in both lists. The macro **POBJ_LIST_MOVE_ELEMENT_BEFORE**() atomically removes the element *elm* from the list referenced by *head* and inserts it into the list referenced by *head_new* before the element *listelm*. If *listelm* value is **TOID_NULL**, the object is inserted at the head of the list. The *field* and *field_new* arguments are the names of the fields of type *POBJ_LIST_ENTRY* in the element structure that are used to connect the elements in both lists. # SEE ALSO # **queue**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmemobj/toid_declare.3.md000066400000000000000000000125721331545616200204530ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(TOID_DECLARE, 3) collection: libpmemobj header: PMDK date: pmemobj API version 2.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (toid_declare.3 -- man page for obj type safety mechanism) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[SEE ALSO](#see-also)
# NAME # **TOID_DECLARE**(), **TOID_DECLARE_ROOT**(), **TOID**(), **TOID_TYPE_NUM**(), **TOID_TYPE_NUM_OF**(), **TOID_VALID**(), **OID_INSTANCEOF**(), **TOID_ASSIGN**(), **TOID_IS_NULL**(), **TOID_EQUALS**(), **TOID_TYPEOF**(), **TOID_OFFSETOF**(), **DIRECT_RW**(), **D_RW**(), **DIRECT_RO**(), **D_RO**() -- libpmemobj type safety mechanism # SYNOPSIS # ```c #include TOID_DECLARE(TYPE, uint64_t type_num) TOID_DECLARE_ROOT(ROOT_TYPE) TOID(TYPE) TOID_TYPE_NUM(TYPE) TOID_TYPE_NUM_OF(TOID oid) TOID_VALID(TOID oid) OID_INSTANCEOF(PMEMoid oid, TYPE) TOID_ASSIGN(TOID o, VALUE) TOID_IS_NULL(TOID o) TOID_EQUALS(TOID lhs, TOID rhs) TOID_TYPEOF(TOID o) TOID_OFFSETOF(TOID o, FILED) DIRECT_RW(TOID oid) D_RW(TOID oid) DIRECT_RO(TOID oid) D_RO(TOID oid) ``` # DESCRIPTION # Operating on untyped object handles, as well as on direct untyped object pointers (*void\**), may be confusing and error-prone. To facilitate type safety, **libpmemobj**(7) defines a set of macros that provide static type enforcement, catching potential errors at compile time. For example, a compile-time error is generated when an attempt is made to assign a handle to an object of one type to the object handle variable of another type of object. The **TOID_DECLARE**() macro declares a typed *OID* of user-defined type *TYPE* and type number *type_num*. The **TOID_DECLARE_ROOT**() macro declares a typed *OID* of user-defined type *ROOT_TYPE* and root object type number **POBJ_ROOT_TYPE_NUM**. The **TOID**() macro declares a handle to an object of type *TYPE*, where *TYPE* is the name of a user-defined structure. The typed *OID* must be declared first using the **TOID_DECLARE**(), **TOID_DECLARE_ROOT**(), **POBJ_LAYOUT_TOID**(3) or **POBJ_LAYOUT_ROOT**(3) macros. The **TOID_TYPE_NUM**() macro returns the type number of the type specified by *TYPE*. The **TOID_TYPE_NUM_OF**() macro returns the type number of the object specified by *oid*. The type number is read from the typed *OID*. The **TOID_VALID**() macro validates whether the type number stored in the object's metadata is equal to the type number read from the typed *OID*. The **OID_INSTANCEOF**() macro checks whether the *oid* is of type *TYPE*. The **TOID_ASSIGN**() macro assigns the object handle *VALUE* to typed *OID* *o*. The **TOID_IS_NULL**() macro evaluates to true if the object handle represented by *o* is **OID_NULL**. The **TOID_EQUALS**() macro evaluates to true if both the *lhs* and *rhs* object handles reference the same persistent object. The **TOID_TYPEOF**() macro returns the type of the object handle represented by typed *OID* *o*. The **TOID_OFFSETOF**() macro returns the offset of the *FIELD* member from the start of the object represented by *o*. The **DIRECT_RW**() macro and its shortened form **D_RW**() return a typed write pointer (*TYPE\**) to an object represented by *oid*. If *oid* is **OID_NULL**, the macro evaluates to NULL. The **DIRECT_RO**() macro and its shortened form **D_RO**() return a typed read-only (const) pointer (*TYPE\**) to an object represented by *oid*. If *oid* is **OID_NULL**, the macro evaluates to NULL. # SEE ALSO # **OID_IS_NULL**(3), **POBJ_LAYOUT_ROOT**(3), **POBJ_LAYOUT_TOID**(3), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmempool/000077500000000000000000000000001331545616200155425ustar00rootroot00000000000000pmdk-1.4.1/doc/libpmempool/libpmempool.7.md000066400000000000000000000247231331545616200205600ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBPMEMPOOL, 7) collection: libpmempool header: PMDK date: pmempool API version 1.3 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libpmempool.7 -- man page for libpmempool) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also)
# NAME # **libpmempool** -- persistent memory pool management library # SYNOPSIS # ```c #include cc _WINUX(,-std=gnu99) ... -lpmempool -lpmem ``` _UNICODE() ##### Library API versioning: ##### ```c _UWFUNC(pmempool_check_version, =q= unsigned major_required, unsigned minor_required=e=) ``` ##### Error handling: ##### ```c _UWFUNC(pmempool_errormsg, void) ``` ##### Other library functions: ##### A description of other **libpmempool** functions can be found on the following manual pages: + health check functions: **pmempool_check_init**(3) + pool set synchronization and transformation: **pmempool_sync**(3) + pool set management functions: **pmempool_rm**(3) # DESCRIPTION # **libpmempool** provides a set of utilities for off-line analysis and manipulation of a *pool*. A *pool* in this manpage means a pmemobj pool, pmemblk pool, pmemlog pool or BTT layout, independent of the underlying storage. Some **libpmempool** functions are required to work without any impact on the *pool* but some may create a new or modify an existing *pool*. **libpmempool** is for applications that need high reliability or built-in troubleshooting. It may be useful for testing and debugging purposes also. **libpmempool** introduces functionality of pool set health check, synchronization, transformation and removal. # CAVEATS # **libpmempool** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. _WINUX(,=q=**libpmempool** requires the **-std=gnu99** compilation flag to build properly.=e=) # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The _UW(pmempool_check_version) function is used to see if the installed **libpmempool** supports the version of the library API required by an application. The easiest way to do this for the application is to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = _U(pmempool_check_version)(PMEMPOOL_MAJOR_VERSION, PMEMPOOL_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. When the version check performed by _UW(pmempool_check_version) is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by _UW(pmempool_check_version) must not be modified or freed. # DEBUGGING AND ERROR HANDLING # If an error is detected during the call to a **libpmempool** function, the application may retrieve an error message describing the reason for the failure from _UW(pmempool_errormsg). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libpmempool** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libpmempool** are typically available on a development system. The normal version, accessed when a program is linked using the **-lpmempool** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version of **libpmempool**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the environment variable **LD_LIBRARY_PATH** to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **PMEMPOOL_LOG_LEVEL** The value of **PMEMPOOL_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **PMEMPOOL_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged (in addition to returning the *errno*-based errors as usual). The same information may be retrieved using _UW(pmempool_errormsg). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **libpmempool** developers. Unless **PMEMPOOL_LOG_FILE** is set, debugging output is written to *stderr*. + **PMEMPOOL_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **PMEMPOOL_LOG_FILE** is not set, output is written to *stderr*. # EXAMPLE # The following example illustrates how the **libpmempool** API is used. The program detects the type and checks consistency of given pool. If there are any issues detected, the pool is automatically repaired. ```c #include _WINUX(,=q= #include =e=) #include #include #include #define PATH "./pmem-fs/myfile" #define CHECK_FLAGS (PMEMPOOL_CHECK_FORMAT_STR|PMEMPOOL_CHECK_REPAIR|\ PMEMPOOL_CHECK_VERBOSE) int main(int argc, char *argv[]) { PMEMpoolcheck *ppc; struct _U(pmempool_check_status) *status; enum pmempool_check_result ret; /* arguments for check */ struct _U(pmempool_check_args) args = { .path = PATH, .backup_path = NULL, .pool_type = PMEMPOOL_POOL_TYPE_DETECT, .flags = CHECK_FLAGS }; /* initialize check context */ if ((ppc = _U(pmempool_check_init)(&args, sizeof(args))) == NULL) { perror("_U(pmempool_check_init)"); exit(EXIT_FAILURE); } /* perform check and repair, answer 'yes' for each question */ while ((status = _U(pmempool_check)(ppc)) != NULL) { switch (status->type) { case PMEMPOOL_CHECK_MSG_TYPE_ERROR: printf("%s\n", status->str.msg); break; case PMEMPOOL_CHECK_MSG_TYPE_INFO: printf("%s\n", status->str.msg); break; case PMEMPOOL_CHECK_MSG_TYPE_QUESTION: printf("%s\n", status->str.msg); status->str.answer = "yes"; break; default: pmempool_check_end(ppc); exit(EXIT_FAILURE); } } /* finalize the check and get the result */ ret = pmempool_check_end(ppc); switch (ret) { case PMEMPOOL_CHECK_RESULT_CONSISTENT: case PMEMPOOL_CHECK_RESULT_REPAIRED: return 0; default: return 1; } } ``` See for more examples using the **libpmempool** API. # ACKNOWLEDGEMENTS # **libpmempool** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **dlclose**(3), **pmempool_check_init**(3), **pmempool_rm**(3), **pmempool_sync**(3), **strerror**(3), **libpmem**(7), **libpmemblk**(7), **libpmemcto**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmempool/pmempool_check_init.3.md000066400000000000000000000232021331545616200222340ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL_CHECK_INIT, 3) collection: libpmempool header: PMDK date: pmempool API version 1.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool_check_init.3 -- man page for pmempool health check functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[EXAMPLE](#example)
[NOTES](#notes)
[SEE ALSO](#see-also)
# NAME # _UW(pmempool_check_init), _UW(pmempool_check), **pmempool_check_end**() -- checks pmempool health # SYNOPSIS # ```c #include _UWFUNCR1UW(PMEMpoolcheck, *pmempool_check_init, struct pmempool_check_args, *args,=q= size_t args_size=e=) _UWFUNCRUW(struct pmempool_check_status, *pmempool_check, PMEMpoolcheck *ppc) enum pmempool_check_result pmempool_check_end(PMEMpoolcheck *ppc); ``` _UNICODE() # DESCRIPTION # To perform the checks provided by **libpmempool**, a *check context* must first be initialized using the _UW(pmempool_check_init) function described in this section. Once initialized, the *check context* is represented by an opaque handle of type *PMEMpoolcheck\**, which is passed to all of the other functions available in **libpmempool** To execute checks, _UW(pmempool_check) must be called iteratively. Each call generates a new check status, represented by a _UWS(pmempool_check_status) structure. Status messages are described later below. When the checks are completed, _UW(pmempool_check) returns NULL. The check must be finalized using **pmempool_check_end**(), which returns an *enum pmempool_check_result* describing the results of the entire check. _UW(pmempool_check_init) initializes the check context. *args* describes parameters of the check context. *args_size* should be equal to the size of the _UWS(pmempool_check_args). _UWS(pmempool_check_args) is defined as follows: _WINUX(=q= ```c struct pmempool_check_argsU { /* path to the pool to check */ const char *path; /* optional backup path */ const char *backup_path; /* type of the pool */ enum pmempool_pool_type pool_type; /* parameters */ int flags; }; struct pmempool_check_argsW { /* path to the pool to check */ const wchar_t *path; /* optional backup path */ const wchar_t *backup_path; /* type of the pool */ enum pmempool_pool_type pool_type; /* parameters */ int flags; }; ``` =e=,=q= ```c struct pmempool_check_args { /* path to the pool to check */ const char *path; /* optional backup path */ const char *backup_path; /* type of the pool */ enum pmempool_pool_type pool_type; /* parameters */ int flags; }; ``` =e=) The *flags* argument accepts any combination of the following values (ORed): + **PMEMPOOL_CHECK_REPAIR** - perform repairs + **PMEMPOOL_CHECK_DRY_RUN** - emulate repairs, not supported on Device DAX + **PMEMPOOL_CHECK_ADVANCED** - perform hazardous repairs + **PMEMPOOL_CHECK_ALWAYS_YES** - do not ask before repairs + **PMEMPOOL_CHECK_VERBOSE** - generate info statuses + **PMEMPOOL_CHECK_FORMAT_STR** - generate string format statuses *pool_type* must match the type of the *pool* being processed. Pool type detection may be enabled by setting *pool_type* to **PMEMPOOL_POOL_TYPE_DETECT**. A pool type detection failure ends the check. *backup_path* may be: + NULL. No backup will be performed. + a non-existent file: *backup_path* will be created and backup will be performed. *path* must be a single file *pool*. + an existing *pool set* file: Backup will be performed as defined by the *backup_path* pool set. *path* must be a pool set, and *backup_path* must have the same structure (the same number of parts with exactly the same size) as the *path* pool set. Backup is supported only if the source *pool set* has no defined replicas. Neither *path* nor *backup_path* may specify a pool set with remote replicas. The _UW(pmempool_check) function starts or resumes the check indicated by *ppc*. When the next status is generated, the check is paused and _UW(pmempool_check) returns a pointer to the _UWS(pmempool_check_status) structure: _WINUX(=q= { ```c struct pmempool_check_statusU { enum pmempool_check_msg_type type; /* type of the status */ struct { const char *msg; /* status message string */ const char *answer; /* answer to message if applicable */ } str; }; struct pmempool_check_statusW { enum pmempool_check_msg_type type; /* type of the status */ struct { const wchar_t *msg; /* status message string */ const wchar_t *answer; /* answer to message if applicable */ } str; }; ``` =e=,=q= ```c struct pmempool_check_status { enum pmempool_check_msg_type type; /* type of the status */ struct { const char *msg; /* status message string */ const char *answer; /* answer to message if applicable */ } str; }; ``` =e=) This structure can describe three types of statuses: + **PMEMPOOL_CHECK_MSG_TYPE_INFO** - detailed information about the check. Generated only if a **PMEMPOOL_CHECK_VERBOSE** flag was set. + **PMEMPOOL_CHECK_MSG_TYPE_ERROR** - An error was encountered. + **PMEMPOOL_CHECK_MSG_TYPE_QUESTION** - question. Generated only if an **PMEMPOOL_CHECK_ALWAYS_YES** flag was not set. It requires *answer* to be set to "yes" or "no" before continuing. After calling _UW(pmempool_check) again, the previously provided _UWS(pmempool_check_status) pointer must be considered invalid. The **pmempool_check_end**() function finalizes the check and releases all related resources. *ppc* is invalid after calling **pmempool_check_end**(). # RETURN VALUE # _UW(pmempool_check_init) returns an opaque handle of type *PMEMpoolcheck\**. If the provided parameters are invalid or the initialization process fails, _UW(pmempool_check_init) returns NULL and sets *errno* appropriately. Each call to _UW(pmempool_check) returns a pointer to a _UWS(pmempool_check_status) structure when a status is generated. When the check completes, _UW(pmempool_check) returns NULL. The **pmempool_check_end**() function returns an *enum pmempool_check_result* summarizing the results of the finalized check. **pmempool_check_end**() can return one of the following values: + **PMEMPOOL_CHECK_RESULT_CONSISTENT** - the *pool* is consistent + **PMEMPOOL_CHECK_RESULT_NOT_CONSISTENT** - the *pool* is not consistent + **PMEMPOOL_CHECK_RESULT_REPAIRED** - the *pool* has issues but all repair steps completed successfully + **PMEMPOOL_CHECK_RESULT_CANNOT_REPAIR** - the *pool* has issues which can not be repaired + **PMEMPOOL_CHECK_RESULT_ERROR** - the *pool* has errors or the check encountered an issue # EXAMPLE # This is an example of a *check context* initialization: ```c struct _U(pmempool_check_args) args = { .path = "/path/to/blk.pool", .backup_path = NULL, .pool_type = PMEMPOOL_POOL_TYPE_BLK, .flags = PMEMPOOL_CHECK_REPAIR | PMEMPOOL_CHECK_DRY_RUN | PMEMPOOL_CHECK_VERBOSE | PMEMPOOL_CHECK_FORMAT_STR }; ``` ```c PMEMpoolcheck *ppc = _U(pmempool_check_init)(&args, sizeof(args)); ``` The check will process a *pool* of type **PMEMPOOL_POOL_TYPE_BLK** located in the path */path/to/blk.pool*. Before the check it will not create a backup of the *pool* (*backup_path == NULL*). If the check finds any issues it will try to perform repair steps (**PMEMPOOL_CHECK_REPAIR**), but it will not make any changes to the *pool* (**PMEMPOOL_CHECK_DRY_RUN**) and it will not perform any dangerous repair steps (no **PMEMPOOL_CHECK_ADVANCED**). The check will ask before performing any repair steps (no **PMEMPOOL_CHECK_ALWAYS_YES**). It will also generate detailed information about the check (**PMEMPOOL_CHECK_VERBOSE**). The **PMEMPOOL_CHECK_FORMAT_STR** flag indicates string format statuses (*struct pmempool_check_status*). Currently this is the only supported status format so this flag is required. # NOTES # Currently, checking the consistency of a *pmemobj* pool is **not** supported. # SEE ALSO # **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libpmempool/pmempool_rm.3.md000066400000000000000000000066201331545616200205570ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL_RM, 3) collection: libpmempool header: PMDK date: pmempool API version 1.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool_rm.3 -- man page for pool set management functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # _UW(pmempool_rm) -- remove persistent memory pool # SYNOPSIS # ```c #include _UWFUNCR1(int, pmempool_rm, *path, int flags) ``` _UNICODE() # DESCRIPTION # The _UW(pmempool_rm) function removes the pool pointed to by *path*. The *path* can point to a regular file, device dax or pool set file. If *path* is a pool set file, _UW(pmempool_rm) will remove all part files from local replicas using **unlink**(2)_WINUX(,=q=, and all remote replicas using **rpmem_remove**(3) (see **librpmem**(7)),=e=) before removing the pool set file itself. The *flags* argument determines the behavior of _UW(pmempool_rm). It is either 0 or the bitwise OR of one or more of the following flags: + **PMEMPOOL_RM_FORCE** - Ignore all errors when removing part files from local _WINUX(,or remote )replicas. + **PMEMPOOL_RM_POOLSET_LOCAL** - Also remove local pool set file. _WINUX(, + **PMEMPOOL_RM_POOLSET_REMOTE** - Also remove remote pool set file.) # RETURN VALUE # On success, _UW(pmempool_rm) returns 0. On error, it returns -1 and sets *errno* accordingly. # SEE ALSO # **rpmem_remove**(3), **unlink**(3), **libpmemlog**(7), **libpmemobj**(7), **librpmem**(7) and **** pmdk-1.4.1/doc/libpmempool/pmempool_sync.3.md000066400000000000000000000156641331545616200211250ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL_SYNC, 3) collection: libpmempool header: PMDK date: pmempool API version 1.3 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool_sync.3 -- man page for pmempool sync and transform) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[NOTES](#notes)
[SEE ALSO](#see-also)
# NAME # _UW(pmempool_sync), _UW(pmempool_transform) -- pool set synchronization and transformation # SYNOPSIS # ```c #include _UWFUNCR1(int, pmempool_sync, *poolset_file,=q= unsigned flags=e=, =q= (EXPERIMENTAL)=e=) _UWFUNCR12(int, pmempool_transform, *poolset_file_src, *poolset_file_dst, unsigned flags, =q= (EXPERIMENTAL)=e=) ``` _UNICODE() # DESCRIPTION # The _UW(pmempool_sync) function synchronizes data between replicas within a pool set. _UW(pmempool_sync) accepts two arguments: * *poolset_file* - a path to a pool set file, * *flags* - a combination of flags (ORed) which modify how synchronization is performed. >NOTE: Only the pool set file used to create the pool should be used for syncing the pool. The following flags are available: * **PMEMPOOL_DRY_RUN** - do not apply changes, only check for viability of synchronization. _UW(pmempool_sync) checks that the metadata of all replicas in a pool set is consistent, i.e. all parts are healthy, and if any of them is not, the corrupted or missing parts are recreated and filled with data from one of the healthy replicas. _WINUX(,=q=If a pool set has the option *SINGLEHDR* (see **poolset**(5)), the internal metadata of each replica is limited to the beginning of the first part in the replica. If the option *NOHDRS* is used, replicas contain no internal metadata. In both cases, only the missing parts or the ones which cannot be opened are recreated with the _UW(pmempool_sync) function.=e=) _UW(pmempool_transform) modifies the internal structure of a pool set. It supports the following operations: * adding one or more replicas, * removing one or more replicas_WINUX(.,=q=, * adding or removing pool set options.=e=) Only one of the above operations can be performed at a time. _UW(pmempool_transform) accepts three arguments: * *poolset_file_src* - pathname of the pool *set* file for the source pool set to be changed, * *poolset_file_dst* - pathname of the pool *set* file that defines the new structure of the pool set, * *flags* - a combination of flags (ORed) which modify how synchronization is performed. The following flags are available: * **PMEMPOOL_DRY_RUN** - do not apply changes, only check for viability of transformation. _WINUX(=q=When adding or deleting replicas, the two pool set files can differ only in the definitions of replicas which are to be added or deleted. One cannot add and remove replicas in the same step. Only one of these operations can be performed at a time. Reordering replicas is not supported. Also, to add a replica it is necessary for its effective size to match or exceed the pool size. Otherwise the whole operation fails and no changes are applied. The effective size of a replica is the sum of sizes of all its part files decreased by 4096 bytes per each part file. The 4096 bytes of each part file is utilized for storing internal metadata of the pool part files.=e=) _WINUX(,=q=When adding or deleting replicas, the two pool set files can differ only in the definitions of replicas which are to be added or deleted. When adding or removing pool set options (see **poolset**(5)), the rest of both pool set files have to be of the same structure. The operation of adding/removing a pool set option can be performed on a pool set with local replicas only. To add/remove a pool set option to/from a pool set with remote replicas, one has to remove the remote replicas first, then add/remove the option, and finally recreate the remote replicas having added/removed the pool set option to/from the remote replicas' poolset files. To add a replica it is necessary for its effective size to match or exceed the pool size. Otherwise the whole operation fails and no changes are applied. If none of the pool set options is used, the effective size of a replica is the sum of sizes of all its part files decreased by 4096 bytes per each part file. The 4096 bytes of each part file is utilized for storing internal metadata of the pool part files. If the option *SINGLEHDR* is used, the effective size of a replica is the sum of sizes of all its part files decreased once by 4096 bytes. In this case only the first part contains internal metadata. If the option *NOHDRS* is used, the effective size of a replica is the sum of sizes of all its part files. In this case none of the parts contains internal metadata.=e=) # RETURN VALUE # _UW(pmempool_sync) and _UW(pmempool_transform) return 0 on success. Otherwise, they return -1 and set *errno* appropriately. # NOTES # The _UW(pmempool_sync) API is experimental and it may change in future versions of the library. The _UW(pmempool_transform) API is experimental and it may change in future versions of the library. # SEE ALSO # **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/librpmem/000077500000000000000000000000001331545616200150325ustar00rootroot00000000000000pmdk-1.4.1/doc/librpmem/librpmem.7.md000066400000000000000000000374271331545616200173450ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBRPMEM, 7) collection: librpmem header: PMDK date: rpmem API version 1.2 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (librpmem.7 -- man page for librpmem) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[TARGET NODE ADDRESS FORMAT](#target-node-address-format)
[REMOTE POOL ATTRIBUTES](#remote-pool-attributes)
[SSH](#ssh)
[FORK](#fork)
[CAVEATS](#caveats)
[LIBRARY API VERSIONING](#library-api-versioning-1)
[ENVIRONMENT](#environment)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also) # NAME # **librpmem** -- remote persistent memory support library (EXPERIMENTAL) # SYNOPSIS # ```c #include cc ... -lrpmem ``` ##### Library API versioning: ##### ```c const char *rpmem_check_version( unsigned major_required, unsigned minor_required); ``` ##### Error handling: ##### ```c const char *rpmem_errormsg(void); ``` ##### Other library functions: ##### A description of other **librpmem** functions can be found on the following manual pages: + **rpmem_create**(3), **rpmem_persist**(3) # DESCRIPTION # **librpmem** provides low-level support for remote access to *persistent memory* (pmem) utilizing RDMA-capable RNICs. The library can be used to remotely replicate a memory region over the RDMA protocol. It utilizes an appropriate persistency mechanism based on the remote node's platform capabilities. **librpmem** utilizes the **ssh**(1) client to authenticate a user on the remote node, and for encryption of the connection's out-of-band configuration data. See **SSH**, below, for details. The maximum replicated memory region size can not be bigger than the maximum locked-in-memory address space limit. See **memlock** in **limits.conf**(5) for more details. This library is for applications that use remote persistent memory directly, without the help of any library-supplied transactions or memory allocation. Higher-level libraries that build on **libpmem**(7) are available and are recommended for most applications, see: + **libpmemobj**(7), a general use persistent memory API, providing memory allocation and transactional operations on variable-sized objects. # TARGET NODE ADDRESS FORMAT # ``` [@][:] ``` The target node address is described by the *hostname* which the client connects to, with an optional *user* name. The user must be authorized to authenticate to the remote machine without querying for password/passphrase. The optional *port* number is used to establish the SSH connection. The default port number is 22. # REMOTE POOL ATTRIBUTES # The *rpmem_pool_attr* structure describes a remote pool and is stored in remote pool's metadata. This structure must be passed to the **rpmem_create**(3) function by caller when creating a pool on remote node. When opening the pool using **rpmem_open**(3) function the appropriate fields are read from pool's metadata and returned back to the caller. ```c #define RPMEM_POOL_HDR_SIG_LEN 8 #define RPMEM_POOL_HDR_UUID_LEN 16 #define RPMEM_POOL_USER_FLAGS_LEN 16 struct rpmem_pool_attr { char signature[RPMEM_POOL_HDR_SIG_LEN]; uint32_t major; uint32_t compat_features; uint32_t incompat_features; uint32_t ro_compat_features; unsigned char poolset_uuid[RPMEM_POOL_HDR_UUID_LEN]; unsigned char uuid[RPMEM_POOL_HDR_UUID_LEN]; unsigned char next_uuid[RPMEM_POOL_HDR_UUID_LEN]; unsigned char prev_uuid[RPMEM_POOL_HDR_UUID_LEN]; unsigned char user_flags[RPMEM_POOL_USER_FLAGS_LEN]; }; ``` The *signature* field is an 8-byte field which describes the pool's on-media format. The *major* field is a major version number of the pool's on-media format. The *compat_features* field is a mask describing compatibility of pool's on-media format optional features. The *incompat_features* field is a mask describing compatibility of pool's on-media format required features. The *ro_compat_features* field is a mask describing compatibility of pool's on-media format features. If these features are not available, the pool shall be opened in read-only mode. The *poolset_uuid* field is an UUID of the pool which the remote pool is associated with. The *uuid* field is an UUID of a first part of the remote pool. This field can be used to connect the remote pool with other pools in a list. The *next_uuid* and *prev_uuid* fields are UUIDs of next and previous replicas respectively. These fields can be used to connect the remote pool with other pools in a list. The *user_flags* field is a 16-byte user-defined flags. # SSH # **librpmem** utilizes the **ssh**(1) client to login and execute the **rpmemd**(1) process on the remote node. By default, **ssh**(1) is executed with the **-4** option, which forces using **IPv4** addressing. For debugging purposes, both the ssh client and the commands executed on the remote node may be overridden by setting the **RPMEM_SSH** and **RPMEM_CMD** environment variables, respectively. See **ENVIRONMENT** for details. # FORK # The **ssh**(1) client is executed by **rpmem_open**(3) and **rpmem_create**(3) after forking a child process using **fork**(2). The application must take this into account when using **wait**(2) and **waitpid**(2), which may return the *PID* of the **ssh**(1) process executed by **librpmem**. If **fork**(2) support is not enabled in **libibverbs**, **rpmem_open**(3) and **rpmem_create**(3) will fail. By default, **fabric**(7) initializes **libibverbs** with **fork**(2) support by calling the **ibv_fork_init**(3) function. See **fi_verbs**(7) for more details. # CAVEATS # **librpmem** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. **librpmem** registers a pool as a single memory region. A Chelsio T4 and T5 hardware can not handle a memory region greater than or equal to 8GB due to a hardware bug. So *pool_size* value for **rpmem_create**(3) and **rpmem_open**(3) using this hardware can not be greater than or equal to 8GB. # LIBRARY API VERSIONING # This section describes how the library API is versioned, allowing applications to work with an evolving API. The **rpmem_check_version**() function is used to see if the installed **librpmem** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = rpmem_check_version(RPMEM_MAJOR_VERSION, RPMEM_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. When the version check performed by **rpmem_check_version**() is successful, the return value is NULL. Otherwise the return value is a static string describing the reason for failing the version check. The string returned by **rpmem_check_version**() must not be modified or freed. # ENVIRONMENT # **librpmem** can change its default behavior based on the following environment variables. These are largely intended for testing and are not normally required. + **RPMEM_SSH**=*ssh_client* Setting this environment variable overrides the default **ssh**(1) client command name. + **RPMEM_CMD**=*cmd* Setting this environment variable overrides the default command executed on the remote node using either **ssh**(1) or the alternative remote shell command specified by **RPMEM_SSH**. **RPMEM_CMD** can contain multiple commands separated by a vertical bar (`|`). Each consecutive command is executed on the remote node in order read from a pool set file. This environment variable is read when the library is initialized, so **RPMEM_CMD** must be set prior to application launch (or prior to **dlopen**(3) if **librpmem** is being dynamically loaded). + **RPMEM_ENABLE_SOCKETS**=0\|1 Setting this variable to 1 enables using **fi_sockets**(7) provider for in-band RDMA connection. The *sockets* provider does not support IPv6. It is required to disable IPv6 system wide if **RPMEM_ENABLE_SOCKETS** == 1 and *target* == localhost (or any other loopback interface address) and **SSH_CONNECTION** variable (see **ssh**(1) for more details) contains IPv6 address after ssh to loopback interface. By default the *sockets* provider is disabled. * **RPMEM_ENABLE_VERBS**=0\|1 Setting this variable to 0 disables using **fi_verbs**(7) provider for in-band RDMA connection. The *verbs* provider is enabled by default. * **RPMEM_MAX_NLANES**=*num* Limit the maximum number of lanes to *num*. See **LANES**, in **rpmem_create**(3), for details. # DEBUGGING AND ERROR HANDLING # If an error is detected during the call to a **librpmem** function, the application may retrieve an error message describing the reason for the failure from **rpmem_errormsg**(). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **librpmem** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **librpmem** are typically available on a development system. The normal version, accessed when a program is linked using the **-lrpmem** option, is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version of **librpmem**, accessed when a program uses the libraries under _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the environment variable **LD_LIBRARY_PATH** to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **RPMEM_LOG_LEVEL** The value of **RPMEM_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - This is the default level when **RPMEM_LOG_LEVEL** is not set. No log messages are emitted at this level. + **1** - Additional details on any errors detected are logged (in addition to returning the *errno*-based errors as usual). The same information may be retrieved using **rpmem_errormsg**(). + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous and fairly obscure tracing information that is likely only useful to the **librpmem** developers. Unless **RPMEM_LOG_FILE** is set, debugging output is written to *stderr*. + **RPMEM_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **RPMEM_LOG_FILE** is not set, logging output is written to *stderr*. # EXAMPLE # The following example uses **librpmem** to create a remote pool on given target node identified by given pool set name. The associated local memory pool is zeroed and the data is made persistent on remote node. Upon success the remote pool is closed. ```c #include #include #include #define POOL_SIZE (32 * 1024 * 1024) #define NLANES 4 unsigned char pool[POOL_SIZE]; int main(int argc, char *argv[]) { int ret; unsigned nlanes = NLANES; /* fill pool_attributes */ struct rpmem_pool_attr pool_attr; memset(&pool_attr, 0, sizeof(pool_attr)); /* create a remote pool */ RPMEMpool *rpp = rpmem_create("localhost", "pool.set", pool, POOL_SIZE, &nlanes, &pool_attr); if (!rpp) { fprintf(stderr, "rpmem_create: %s\n", rpmem_errormsg()); return 1; } /* store data on local pool */ memset(pool, 0, POOL_SIZE); /* make local data persistent on remote node */ ret = rpmem_persist(rpp, 0, POOL_SIZE, 0); if (ret) { fprintf(stderr, "rpmem_persist: %s\n", rpmem_errormsg()); return 1; } /* close the remote pool */ ret = rpmem_close(rpp); if (ret) { fprintf(stderr, "rpmem_close: %s\n", rpmem_errormsg()); return 1; } return 0; } ``` # NOTE # The **librpmem** API is experimental and may be subject to change in the future. However, using the remote replication in **libpmemobj**(7) is safe and backward compatibility will be preserved. # ACKNOWLEDGEMENTS # **librpmem** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **rpmemd**(1), **ssh**(1), **fork**(2), **dlclose**(3), **dlopen**(3), **ibv_fork_init**(3), **rpmem_create**(3), **rpmem_open**(3), **rpmem_persist**(3), **strerror**(3), **limits.conf**(5), **fabric**(7), **fi_sockets**(7), **fi_verbs**(7), **libpmem**(7), **libpmemblk**(7), **libpmemcto**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/librpmem/rpmem_create.3.md000066400000000000000000000234021331545616200201610ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(RPMEM_CREATE, 3) collection: librpmem header: PMDK date: rpmem API version 1.2 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (rpmem_create.3 -- man page for most commonly used librpmem functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[NOTES](#notes)
[SEE ALSO](#see-also)
# NAME # **rpmem_create**(), **rpmem_open**(), **rpmem_set_attr**(), **rpmem_close**(), **rpmem_remove**() -- most commonly used functions for remote access to *persistent memory* # SYNOPSIS # ```c #include RPMEMpool *rpmem_create(const char *target, const char *pool_set_name, void *pool_addr, size_t pool_size, unsigned *nlanes, const struct rpmem_pool_attr *create_attr); RPMEMpool *rpmem_open(const char *target, const char *pool_set_name, void *pool_addr, size_t pool_size, unsigned *nlanes, struct rpmem_pool_attr *open_attr); int rpmem_set_attr(RPMEMpool *rpp, const struct rpmem_pool_attr *attr); int rpmem_close(RPMEMpool *rpp); int rpmem_remove(const char *target, const char *pool_set_name, int flags); ``` # DESCRIPTION # The **rpmem_create**() function creates a remote pool on a given *target* node, using pool *set* file *pool_set_name* to map the remote pool. *pool_set_name* is a relative path in the root config directory on the *target* node. For pool set file format and options see **poolset**(5). *pool_addr* is a pointer to the associated local memory pool with size *pool_size*. Both *pool_addr* and *pool_size* must be aligned to the system's page size (see **sysconf**(3)). The size of the remote pool must be at least *pool_size*. See **REMOTE POOL SIZE**, below, for details. *nlanes* points to the maximum number of lanes which the caller is requesting. Upon successful creation of the remote pool, \**nlanes* is set to the maximum number of lanes supported by both the local and remote nodes. See **LANES**, below, for details. The *create_attr* structure contains the attributes used for creating the remote pool. If the *create_attr* structure is not NULL, a pool with internal metadata is created. The metadata is stored in the first 4096 bytes of the pool and can be read when opening the remote pool with **rpmem_open**(). To prevent user from overwriting the pool metadata, this region is not accessible to the user via **rpmem_persist**(). If *create_attr* is NULL or zeroed, remote pool set file must contain the *NOHDRS* option. In that case the remote pool is created without internal metadata in it and the entire pool space is available to the user. See **rpmem_persist**(3) for details. The **rpmem_open**() function opens the existing remote pool with *set* file *pool_set_name* on remote node *target*. *pool_set_name* is a relative path in the root config directory on the *target* node. *pool_addr* is a pointer to the associated local memory pool of size *pool_size*. Both *pool_addr* and *pool_size* must be aligned to the system's page size (see **sysconf**(3)). The size of the remote pool must be at least *pool_size*. See **REMOTE POOL SIZE**, below, for details. *nlanes* points to the maximum number of lanes which the caller is requesting. Upon successful opening of the remote pool, \**nlanes* is set to the maximum number of lanes supported by both the local and remote nodes. See **LANES**, below, for details. The **rpmem_set_attr**() function overwrites the pool's attributes. The *attr* structure contains the attributes used for overwriting the remote pool attributes that were passed to **rpmem_create**() at pool creation. If *attr* is NULL, a zeroed structure with attributes will be used. New attributes are stored in the pool's metadata. The **rpmem_close**() function closes the remote pool *rpp*. All resources are released on both the local and remote nodes. The remote pool itself persists on the remote node and may be re-opened at a later time using **rpmem_open**(). The **rpmem_remove**() function removes the remote pool with *set* file name *pool_set_name* from node *target*. The *pool_set_name* is a relative path in the root config directory on the *target* node. By default only the pool part files are removed; the pool *set* file is left untouched. If the pool is not consistent, the **rpmem_remove**() function fails. The *flags* argument determines the behavior of **rpmem_remove**(). *flags* may be either 0 or the bitwise OR of one or more of the following flags: + **RPMEM_REMOVE_FORCE** - Ignore errors when opening an inconsistent pool. The pool *set* file must still be in appropriate format for the pool to be removed. + **RPMEM_REMOVE_POOL_SET** - Remove the pool *set* file after removing the pool described by this pool set. # RETURN VALUE # On success, **rpmem_create**() returns an opaque handle to the remote pool for use in subsequent **librpmem** calls. If any error prevents the remote pool from being created, **rpmem_create**() returns NULL and sets *errno* appropriately. On success, **rpmem_open**() returns an opaque handle to the remote pool for subsequent **librpmem** calls. If the *open_attr* argument is not NULL, the remote pool attributes are returned in the provided structure. If the remote pool was created without internal metadata, zeroes are returned in the *open_attr* structure on successful call to **rpmem_open**(). If any error prevents the remote pool from being opened, **rpmem_open**() returns NULL and sets *errno* appropriately. On success, **rpmem_set_attr**() returns 0. On error, it returns -1 and sets *errno* appropriately. On success, **rpmem_close**() returns 0. On error, it returns a non-zero value and sets *errno* appropriately. On success, **rpmem_remove**() returns 0. On error, it returns a non-zero value and sets *errno* appropriately. # NOTES # ## REMOTE POOL SIZE ## The size of a remote pool depends on the configuration in the pool set file on the remote node (see **poolset**(5)). If no pool set options is used in the remote pool set file, the remote pool size is the sum of the sizes of all part files, decreased by 4096 bytes per part file. 4096 bytes of each part file are utilized for storing internal metadata. If the *SINGLEHDR* option is used in the remote pool set file, the remote pool size is the sum of sizes of all part files, decreased once by 4096 bytes. In this case only the first part contains internal metadata. If a remote pool set file contains the *NOHDRS* option, the remote pool size is the sum of sizes of all its part files. In this case none of the parts contains internal metadata. For other consequences of using the *SINGLEHDR* and *NOHDRS* options see **rpmem_persist**(3). **RPMEM_MIN_PART** and **RPMEM_MIN_POOL** in **\** define the minimum size allowed by **librpmem** for a part file and a remote pool, respectively. ## LANES ## The term *lane* means an isolated path of execution. The underlying hardware utilized by both local and remote nodes may have limited resources that restrict the maximum number of parallel **rpmem_persist**(3) operations. The maximum number of supported lanes is returned by the **rpmem_open**() and **rpmem_create**() function calls. The caller passes the maximum number of lanes requested in \**nlanes*. If the pool is successfully created or opened, \**nlanes* is updated to reflect the minimum of the number of lanes requested by the caller and the maximum number of lanes supported by underlying hardware. The application is obligated to use at most the returned number of lanes in parallel. **rpmem_persist**(3) does not provide any locking mechanism; thus any serialization of calls must be performed by the application if required. Each lane requires a separate connection, represented by a file descriptor. If the system runs out of free file descriptors during **rpmem_create**() or **rpmem_open**(), these functions will fail. See **nofile** in **limits.conf**(5) for more details. # SEE ALSO # **rpmem_persist**(3), **sysconf**(3), **limits.conf**(5), **libpmemobj**(7), **librpmem**(7) and **** pmdk-1.4.1/doc/librpmem/rpmem_persist.3.md000066400000000000000000000117351331545616200204150ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(RPMEM_PERSIST, 3) collection: librpmem header: PMDK date: rpmem API version 1.2 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (rpmem_persist.3 -- man page for rpmem persist and read functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **rpmem_persist**(), **rpmem_read**(), -- functions to copy and read remote pools # SYNOPSIS # ```c #include int rpmem_persist(RPMEMpool *rpp, size_t offset, size_t length, unsigned lane); int rpmem_deep_persist(RPMEMpool *rpp, size_t offset, size_t length, unsigned lane); int rpmem_read(RPMEMpool *rpp, void *buff, size_t offset, size_t length, unsigned lane); ``` # DESCRIPTION # The **rpmem_persist**() function copies data of given *length* at given *offset* from the associated local memory pool and makes sure the data is persistent on the remote node before the function returns. The remote node is identified by the *rpp* handle which must be returned from either **rpmem_open**(3) or **rpmem_create**(3). The *offset* is relative to the *pool_addr* specified in the **rpmem_open**(3) or **rpmem_create**(3) call. If the remote pool was created using **rpmem_create**() with non-NULL *create_attr* argument, *offset* has to be greater or equal to 4096. In that case the first 4096 bytes of the pool is used for storing the pool matadata and cannot be overwritten. If the pool was created with NULL *create_attr* argument, the pool metadata is not stored with the pool and *offset* can be any nonnegative number. The *offset* and *length* combined must not exceed the *pool_size* passed to **rpmem_open**(3) or **rpmem_create**(3). The **rpmem_persist**() operation is performed using the given *lane* number. The lane must be less than the value returned by **rpmem_open**(3) or **rpmem_create**(3) through the *nlanes* argument (so it can take a value from 0 to *nlanes* - 1). The **rpmem_deep_persist**() function works in the same way as **rpmem_persist**(3) function, but additionaly it flushes the data to the lowest possible persistency domain available from software. Please see **pmem_deep_persist**(3) for details. The **rpmem_read**() function reads *length* bytes of data from a remote pool at *offset* and copies it to the buffer *buff*. The operation is performed on the specified *lane*. The lane must be less than the value returned by **rpmem_open**(3) or **rpmem_create**(3) through the *nlanes* argument (so it can take a value from 0 to *nlanes* - 1). The *rpp* must point to a remote pool opened or created previously by **rpmem_open**(3) or **rpmem_create**(3). # RETURN VALUE # The **rpmem_persist**() function returns 0 if the entire memory area was made persistent on the remote node. Otherwise it returns a non-zero value and sets *errno* appropriately. The **rpmem_read**() function returns 0 if the data was read entirely. Otherwise it returns a non-zero value and sets *errno* appropriately. # SEE ALSO # **rpmem_create**(3), **rpmem_open**(3), **rpmem_persist**(3), **sysconf**(3), **limits.conf**(5), **libpmemobj**(7) and **** pmdk-1.4.1/doc/libvmem/000077500000000000000000000000001331545616200146565ustar00rootroot00000000000000pmdk-1.4.1/doc/libvmem/libvmem.7.md000066400000000000000000000273361331545616200170130ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBVMEM, 7) collection: libvmem header: PMDK date: vmem API version 1.1 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libvmem.7 -- man page for libvmem) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[MANAGING LIBRARY BEHAVIOR](#managing-library-behavior)
[DEBUGGING AND ERROR HANDLING](#debugging-and-error-handling)
[EXAMPLE](#example)
[BUGS](#bugs)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also)
# NAME # **libvmem** -- volatile memory allocation library # SYNOPSIS # ```c #include cc ... -lvmem ``` _UNICODE() ##### Managing overall library behavior: ##### ```c _UWFUNC(vmem_check_version, =q= unsigned major_required, unsigned minor_required=e=) void vmem_set_funcs( void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s), void (*print_func)(const char *s)); ``` ##### Error handling: ##### ```c _UWFUNC(vmem_errormsg, void) ``` ##### Other library functions: ##### A description of other **libvmem** functions can be found on the following manual pages: + memory pool management: **vmem_create**(3) + memory allocation related functions: **vmem_malloc**(3) # DESCRIPTION # **libvmem** provides common *malloc*-like interfaces to memory pools built on memory-mapped files. These interfaces are for traditional **volatile** memory allocation but, unlike the functions described in **malloc**(3), the memory managed by **libvmem** may have different attributes, depending on the file system containing the memory-mapped files. In particular, **libvmem** is part of the *Persistent Memory Development Kit* because it is sometimes useful to use non-volatile memory as a volatile memory pool, leveraging its capacity, cost, or performance characteristics. **libvmem** uses the **mmap**(2) system call to create a pool of volatile memory. The library is most useful when used with *Direct Access* storage (DAX), which is memory-addressable persistent storage that supports load/store access without being paged via the system page cache. A Persistent Memory-aware file system is typically used to provide this type of access. Memory-mapping a file from a Persistent Memory-aware file system provides the raw memory pools, and this library supplies the more familiar *malloc*-like interfaces on top of those pools. Under normal usage, **libvmem** will never print messages or intentionally cause the process to exit. Exceptions to this are prints caused by calls to **vmem_stats_print**(3), or by enabling debugging as described under **DEBUGGING AND ERROR HANDLING** below. The library uses **pthreads** to be fully MT-safe, but never creates or destroys threads itself. The library does not make use of any signals, networking, and never calls **select**(2) or **poll**(2). The system memory allocation routines like **malloc**(3) and **free**(3) are used by **libvmem** for managing a small amount of run-time state, but applications are allowed to override these calls if necessary (see the description of **vmem_set_funcs**() below). **libvmem** interfaces are grouped into three categories: those that manage memory pools, those providing the basic memory allocation functions, and those interfaces less commonly used for managing the overall library behavior. # MANAGING LIBRARY BEHAVIOR # The _UW(vmem_check_version) function is used to see if the installed **libvmem** supports the version of the library API required by an application. The easiest way to do this is for the application to supply the compile-time version information, supplied by defines in **\**, like this: ```c reason = _U(vmem_check_version)(VMEM_MAJOR_VERSION, VMEM_MINOR_VERSION); if (reason != NULL) { /* version check failed, reason string tells you why */ } ``` Any mismatch in the major version number is considered a failure, but a library with a newer minor version number will pass this check since increasing minor versions imply backwards compatibility. An application can also check specifically for the existence of an interface by checking for the version where that interface was introduced. These versions are documented in this man page as follows: unless otherwise specified, all interfaces described here are available in version 1.0 of the library. Interfaces added after version 1.0 will contain the text *introduced in version x.y* in the section of this manual describing the feature. When the version check is successful, _UW(vmem_check_version) returns NULL. Otherwise, _UW(vmem_check_version) returns a static string describing the reason for failing the version check. The returned string must not be modified or freed. The **vmem_set_funcs**() function allows an application to override some interfaces used internally by **libvmem**. Passing NULL for any of the handlers will cause the **libvmem** default function to be used. The only functions in the malloc family used by the library are represented by the first four arguments to **vmem_set_funcs**(). While the library does not make heavy use of the system malloc functions, it does allocate approximately 4-8 kilobytes for each memory pool in use. The *print_func* function is called by **libvmem** when the **vmem_stats_print**() entry point is used, or when additional tracing is enabled in the debug version of the library as described in **DEBUGGING AND ERROR HANDLING**, below. The default *print_func* used by the library prints to the file specified by the **VMEM_LOG_FILE** environment variable, or to *stderr* if that variable is not set. # CAVEATS # **libvmem** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # DEBUGGING AND ERROR HANDLING # If an error is detected during the call to a **libvmem** function, the application may retrieve an error message describing the reason for the failure from _UW(vmem_errormsg). This function returns a pointer to a static buffer containing the last error message logged for the current thread. If *errno* was set, the error message may include a description of the corresponding error code as returned by **strerror**(3). The error message buffer is thread-local; errors encountered in one thread do not affect its value in other threads. The buffer is never cleared by any library function; its content is significant only when the return value of the immediately preceding call to a **libvmem** function indicated an error, or if *errno* was set. The application must not modify or free the error message string, but it may be modified by subsequent calls to other library functions. Two versions of **libvmem** are typically available on a development system. The normal version is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version, accessed when using libraries from _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the **LD_LIBRARY_PATH** environment variable to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **VMEM_LOG_LEVEL** The value of **VMEM_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - Tracing is disabled. This is the default level when **VMEM_LOG_LEVEL** is not set. Only statistics are logged, and then only in response to a call to **vmem_stats_print**(). + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous tracing information about all memory allocations and deallocations. Unless **VMEM_LOG_FILE** is set, debugging output is written to *stderr*. + **VMEM_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **VMEM_LOG_FILE** is not set, output is written to *stderr*. # EXAMPLE # The following example creates a memory pool, allocates some memory to contain the string "hello, world", and then frees that memory. ```c #include #include #include #include int main(int argc, char *argv[]) { VMEM *vmp; char *ptr; /* create minimum size pool of memory */ if ((vmp = _U(vmem_create)("/pmem-fs", VMEM_MIN_POOL)) == NULL) { perror("_U(vmem_create)"); exit(1); } if ((ptr = vmem_malloc(vmp, 100)) == NULL) { perror("vmem_malloc"); exit(1); } strcpy(ptr, "hello, world"); /* give the memory back */ vmem_free(vmp, ptr); /* ... */ vmem_delete(vmp); } ``` See for more examples using the **libvmem** API. # BUGS # Unlike the normal **malloc**(3), which asks the system for additional memory when it runs out, **libvmem** allocates the size it is told to and never attempts to grow or shrink that memory pool. # ACKNOWLEDGEMENTS # **libvmem** depends on jemalloc, written by Jason Evans, to do the heavy lifting of managing dynamic memory allocation. See: **libvmem** builds on the persistent memory programming model recommended by the SNIA NVM Programming Technical Work Group: # SEE ALSO # **mmap**(2), **dlclose**(3), **malloc**(3), **strerror**(3), **vmem_create**(3), **vmem_malloc**(3), and **** On Linux: **jemalloc**(3), **pthreads**(7) On FreeBSD: **pthread**(3) pmdk-1.4.1/doc/libvmem/vmem_create.3.md000066400000000000000000000171551331545616200176410ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(VMEM_CREATE, 3) collection: libvmem header: PMDK date: vmem API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (vmem_create.3 -- man page for volatile memory pool management functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # _UW(vmem_create), **vmem_create_in_region**(), **vmem_delete**(), **vmem_check**(), **vmem_stats_print**() -- volatile memory pool management # SYNOPSIS # ```c #include _UWFUNCR1(VMEM, *vmem_create, *dir, size_t size) VMEM *vmem_create_in_region(void *addr, size_t size); void vmem_delete(VMEM *vmp); int vmem_check(VMEM *vmp); void vmem_stats_print(VMEM *vmp, const char *opts); ``` _UNICODE() # DESCRIPTION # To use **libvmem**, a *memory pool* is first created. This is most commonly done with the _UW(vmem_create) function described below. The other **libvmem** functions are for less common cases, where applications have special needs for creating pools or examining library state. The _UW(vmem_create) function creates a memory pool and returns an opaque memory pool handle of type *VMEM\**. The handle is then used with **libvmem** functions such as **vmem_malloc**() and **vmem_free**() to provide the familiar *malloc*-like programming model for the memory pool. The pool is created by allocating a temporary file in the directory *dir*, in a fashion similar to **tmpfile**(3), so that the file name does not appear when the directory is listed, and the space is automatically freed when the program terminates. *size* bytes are allocated and the resulting space is memory-mapped. The minimum *size* value allowed by the library is defined in **\** as **VMEM_MIN_POOL**. The maximum allowed size is not limited by **libvmem**, but by the file system on which *dir* resides. The *size* passed in is the raw size of the memory pool. **libvmem** will use some of that space for its own metadata, so the usable space will be less. _UW(vmem_create) can also be called with the **dir** argument pointing to a device DAX. In that case the entire device will serve as a volatile pool. Device DAX is the device-centric analogue of Filesystem DAX. It allows memory ranges to be allocated and mapped without need of an intervening file system. For more information please see **ndctl-create-namespace**(1). **vmem_create_in_region**() is an alternate **libvmem** entry point for creating a memory pool. It is for the rare case where an application needs to create a memory pool from an already memory-mapped region. Instead of allocating space from a file system, **vmem_create_in_region**() is given the memory region explicitly via the *addr* and *size* arguments. Any data in the region is lost by calling **vmem_create_in_region**(), which will immediately store its own data structures for managing the pool there. As with _UW(vmem_create), the minimum *size* allowed is defined as **VMEM_MIN_POOL**. The *addr* argument must be page aligned. Undefined behavior occurs if *addr* does not point to a contiguous memory region in the virtual address space of the calling process, or if the *size* is larger than the actual size of the memory region pointed to by *addr*. The **vmem_delete**() function releases the memory pool *vmp*. If the memory pool was created using _UW(vmem_create), deleting it allows the space to be reclaimed. The **vmem_check**() function performs an extensive consistency check of all **libvmem** internal data structures in memory pool *vmp*. Since an error return indicates memory pool corruption, applications should not continue to use a pool in this state. Additional details about errors found are logged when the log level is at least 1 (see **DEBUGGING AND ERROR HANDLING** in **libvmem**(7)). During the consistency check performed by **vmem_check**(), other operations on the same memory pool are locked out. The checks are all read-only; **vmem_check**() never modifies the memory pool. This function is mostly useful for **libvmem** developers during testing/debugging. The **vmem_stats_print**() function produces messages containing statistics about the given memory pool. Output is sent to *stderr* unless the user sets the environment variable **VMEM_LOG_FILE**, or the application supplies a replacement *print_func* (see **MANAGING LIBRARY BEHAVIOR** in **libvmem**(7)). The *opts* string can either be NULL or it can contain a list of options that change the statistics printed. General information that never changes during execution can be omitted by specifying "g" as a character within the opts string. The characters "m" and "a" can be specified to omit merged arena and per arena statistics, respectively; "b" and "l" can be specified to omit per size class statistics for bins and large objects, respectively. Unrecognized characters are silently ignored. Note that thread caching may prevent some statistics from being completely up to date. See **jemalloc**(3) for more detail (the description of the available *opts* above was taken from that man page). # RETURN VALUE # On success, _UW(vmem_create) returns an opaque memory pool handle of type *VMEM\**. On error, it returns NULL and sets *errno* appropriately. On success, **vmem_create_in_region**() returns an opaque memory pool handle of type *VMEM\**. On error, it returns NULL and sets *errno* appropriately. The **vmem_delete**() function returns no value. The **vmem_check**() function returns 1 if the memory pool is found to be consistent, and 0 if the check was performed but the memory pool is not consistent. If the check could not be performed, **vmem_check**() returns -1. The **vmem_stats_print**() function returns no value. # SEE ALSO # **ndctl-create-namespace**(1), **jemalloc**(3), **tmpfile**(3), **libvmem**(7) and **** pmdk-1.4.1/doc/libvmem/vmem_malloc.3.md000066400000000000000000000200021331545616200176260ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(VMEM_MALLOC, 3) collection: libvmem header: PMDK date: vmem API version 1.1 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (vmem_malloc.3 -- man page for memory allocation related functions) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RETURN VALUE](#return-value)
[SEE ALSO](#see-also)
# NAME # **vmem_malloc**(), **vmem_calloc**(), **vmem_realloc**(), **vmem_free**(), **vmem_aligned_alloc**(), **vmem_strdup**(), **vmem_wcsdup**(), **vmem_malloc_usable_size**() -- memory allocation related functions # SYNOPSIS # ```c #include void *vmem_malloc(VMEM *vmp, size_t size); void vmem_free(VMEM *vmp, void *ptr); void *vmem_calloc(VMEM *vmp, size_t nmemb, size_t size); void *vmem_realloc(VMEM *vmp, void *ptr, size_t size); void *vmem_aligned_alloc(VMEM *vmp, size_t alignment, size_t size); char *vmem_strdup(VMEM *vmp, const char *s); wchar_t *vmem_wcsdup(VMEM *vmp, const wchar_t *s); size_t vmem_malloc_usable_size(VMEM *vmp, void *ptr); ``` # DESCRIPTION # This section describes the *malloc*-like API provided by **libvmem**(7). These functions provide the same semantics as their libc namesakes, but operate on the memory pools specified by their first arguments. The **vmem_malloc**() function provides the same semantics as **malloc**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. It allocates specified *size* bytes. The **vmem_free**() function provides the same semantics as **free**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. It frees the memory space pointed to by *ptr*, which must have been returned by a previous call to **vmem_malloc**(), **vmem_calloc**() or **vmem_realloc**() for *the same pool of memory*. If *ptr* is NULL, no operation is performed. The **vmem_calloc**() function provides the same semantics as **calloc**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. It allocates memory for an array of *nmemb* elements of *size* bytes each. The memory is set to zero. The **vmem_realloc**() function provides the same semantics as **realloc**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. It changes the size of the memory block pointed to by *ptr* to *size* bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will *not* be initialized. Unless *ptr* is NULL, it must have been returned by an earlier call to **vmem_malloc**(), **vmem_calloc**() or **vmem_realloc**(). If *ptr* is NULL, then the call is equivalent to *vmem_malloc(vmp, size)*, for all values of *size*; if *size* is equal to zero, and *ptr* is not NULL, then the call is equivalent to *vmem_free(vmp, ptr)*. The **vmem_aligned_alloc**() function provides the same semantics as **aligned_alloc**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. It allocates *size* bytes from the memory pool. The memory address will be a multiple of *alignment*, which must be a power of two. The **vmem_strdup**() function provides the same semantics as **strdup**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. Memory for the new string is obtained with **vmem_malloc**(), on the given memory pool, and can be freed with **vmem_free**() on the same memory pool. The **vmem_wcsdup**() function provides the same semantics as **wcsdup**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. Memory for the new string is obtained with **vmem_malloc**(), on the given memory pool, and can be freed with **vmem_free**() on the same memory pool. The **vmem_malloc_usable_size**() function provides the same semantics as **malloc_usable_size**(3), but operates on the memory pool *vmp* instead of the process heap supplied by the system. # RETURN VALUE # On success, **vmem_malloc**() returns a pointer to the allocated memory. If *size* is 0, then **vmem_malloc**() returns either NULL, or a unique pointer value that can later be successfully passed to **vmem_free**(). If **vmem_malloc**() is unable to satisfy the allocation request, it returns NULL and sets *errno* appropriately. The **vmem_free**() function returns no value. Undefined behavior occurs if frees do not correspond to allocated memory from the same memory pool. On success, **vmem_calloc**() returns a pointer to the allocated memory. If *nmemb* or *size* is 0, then **vmem_calloc**() returns either NULL, or a unique pointer value that can later be successfully passed to **vmem_free**(). If **vmem_calloc**() is unable to satisfy the allocation request, it returns NULL and sets *errno* appropriately. On success, **vmem_realloc**() returns a pointer to the allocted memory, which may be different from *ptr*. If the area pointed to was moved, a *vmem_free(vmp, ptr)* is done. If **vmem_realloc**() is unable to satisfy the allocation request, it returns NULL and sets *errno* appropriately. On success, **vmem_aligned_alloc**() returns a pointer to the allocated memory. If **vmem_aligned_alloc**() is unable to satisfy the allocation request, it returns NULL and sets *errno* appropriately. On success, **vmem_strdup**() returns a pointer to a new string which is a duplicate of the string *s*. If **vmem_strdup**() is unable to satisfy the allocation request, it returns NULL and sets *errno* appropriately. On success, **vmem_wcsdup**() returns a pointer to a new wide character string which is a duplicate of the wide character string *s*. If **vmem_wcsdup**() is unable to satisfy the allocation request, it returns NULL and sets *errno* appropriately. The **vmem_malloc_usable_size**() function returns the number of usable bytes in the block of allocated memory pointed to by *ptr*, a pointer to a block of memory allocated by **vmem_malloc**() or a related function. If *ptr* is NULL, 0 is returned. # SEE ALSO # **calloc**(3), **free**(3), **malloc**(3), **malloc_usable_size**(3), **realloc**(3), **strdup**(3), **wcsdup**(3) **libvmem(7)** and **** pmdk-1.4.1/doc/libvmmalloc/000077500000000000000000000000001331545616200155245ustar00rootroot00000000000000pmdk-1.4.1/doc/libvmmalloc/libvmmalloc.7.md000066400000000000000000000274131331545616200205230ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(LIBVMMALLOC, 7) collection: libvmmalloc header: PMDK date: vmmalloc API version 1.1 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (libvmmalloc.7 -- man page for libvmmalloc) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[ENVIRONMENT](#environment)
[CAVEATS](#caveats)
[DEBUGGING](#debugging)
[NOTES](#notes)
[BUGS](#bugs)
[ACKNOWLEDGEMENTS](#acknowledgements)
[SEE ALSO](#see-also) # NAME # **libvmmalloc** -- general purpose volatile memory allocation library # SYNOPSIS # ``` $ LD_PRELOAD=libvmmalloc.so command [ args... ] ``` or ```c #include #ifndef __FreeBSD__ #include #else #include #endif #include cc [ flag... ] file... -lvmmalloc [ library... ] ``` ```c void *malloc(size_t size); void free(void *ptr); void *calloc(size_t number, size_t size); void *realloc(void *ptr, size_t size); int posix_memalign(void **memptr, size_t alignment, size_t size); void *aligned_alloc(size_t alignment, size_t size); void *memalign(size_t alignment, size_t size); void *valloc(size_t size); void *pvalloc(size_t size); size_t malloc_usable_size(const void *ptr); void cfree(void *ptr); ``` # DESCRIPTION # **libvmmalloc** transparently converts all dynamic memory allocations into Persistent Memory allocations. The typical usage of **libvmmalloc** does not require any modification of the target program. It is enough to load **libvmmalloc** before all other libraries by setting the environment variable **LD_PRELOAD**. When used in that way, **libvmmalloc** interposes the standard system memory allocation routines, as defined in **malloc**(3), **posix_memalign**(3) and **malloc_usable_size**(3), and provides that all dynamic memory allocations are made from a *memory pool* built on a memory-mapped file, instead of the system heap. The memory managed by **libvmmalloc** may have different attributes, depending on the file system containing the memory-mapped file. In particular, **libvmmalloc** is part of the *Persistent Memory Development Kit* because it is sometimes useful to use non-volatile memory as a volatile memory pool, leveraging its capacity, cost, or performance characteristics. **libvmmalloc** may be also linked to the program, by providing the **-lvmmalloc* argument to the linker. Then it becomes the default memory allocator for the program. >NOTE: Due to the fact the library operates on a memory-mapped file, **it may not work properly with programs that perform fork(2) not followed by exec(3).** There are two variants of experimental **fork**(2) support available in libvmmalloc. The desired library behavior may be selected by setting the **VMMALLOC_FORK** environment variable. By default variant #1 is enabled. See **ENVIRONMENT** for more details. **libvmmalloc** uses the **mmap**(2) system call to create a pool of volatile memory. The library is most useful when used with *Direct Access* storage (DAX), which is memory-addressable persistent storage that supports load/store access without being paged via the system page cache. A Persistent Memory-aware file system is typically used to provide this type of access. Memory-mapping a file from a Persistent Memory-aware file system provides the raw memory pools, and this library supplies the traditional *malloc* interfaces on top of those pools. The memory pool acting as a system heap replacement is created automatically at library initialization time. The user may control its location and size by setting the environment variables described in **ENVIRONMENT**, below. The allocated file space is reclaimed when the process terminates or in case of system crash. Under normal usage, **libvmmalloc** will never print messages or intentionally cause the process to exit. The library uses **pthreads**(7) to be fully MT-safe, but never creates or destroys threads itself. The library does not make use of any signals, networking, and never calls **select**(2) or **poll**(2). # ENVIRONMENT # The **VMMALLOC_POOL_DIR** and **VMMALLOC_POOL_SIZE** environment variables **must** be set for **libvmmalloc** to work properly. If either of them is not specified, or if their values are not valid, the library prints an appropriate error message and terminates the process. Any other environment variables are optional. + **VMMALLOC_POOL_DIR**=*path* Specifies a path to the directory where the memory pool file should be created. The directory must exist and be writable. + **VMMALLOC_POOL_SIZE**=*len* Defines the desired size (in bytes) of the memory pool file. It must be not less than the minimum allowed size **VMMALLOC_MIN_POOL** as defined in **\**. >NOTE: Due to the fact the library adds some metadata to the memory pool, the amount of actual usable space is typically less than the size of the memory pool file. + **VMMALLOC_FORK**=*val* (EXPERIMENTAL) **VMMALLOC_FORK** controls the behavior of **libvmmalloc** in case of **fork**(3), and can be set to the following values: + **0** - **fork**(2) support is disabled. The behavior of **fork**(2) is undefined in this case, but most likely results in memory pool corruption and a program crash due to segmentation fault. + **1** - The memory pool file is remapped with the **MAP_PRIVATE** flag before the fork completes. From this moment, any access to memory that modifies the heap pages, both in the parent and in the child process, will trigger creation of a copy of those pages in RAM (copy-on-write). The benefit of this approach is that it does not significantly increase the time of the initial fork operation, and does not require additional space on the file system. However, all subsequent memory allocations, and modifications of any memory allocated before fork, will consume system memory resources instead of the memory pool. This is the default option if **VMMALLOC_FORK** is not set. + **2** - A copy of the entire memory pool file is created for the use of the child process. This requires additional space on the file system, but both the parent and the child process may still operate on their memory pools, not consuming system memory resources. >NOTE: In case of large memory pools, creating a copy of the pool file may stall the fork operation for a quite long time. + **3** - The library first attempts to create a copy of the memory pool (as for option #2), but if it fails (i.e. because of insufficient free space on the file system), it will fall back to option #1. >NOTE: Options **2** and **3** are not currently supported on FreeBSD. Environment variables used for debugging are described in **DEBUGGING**, below. # CAVEATS # **libvmmalloc** relies on the library destructor being called from the main thread. For this reason, all functions that might trigger destruction (e.g. **dlclose**(3)) should be called in the main thread. Otherwise some of the resources associated with that thread might not be cleaned up properly. # DEBUGGING # Two versions of **libvmmalloc** are typically available on a development system. The normal version is optimized for performance. That version skips checks that impact performance and never logs any trace information or performs any run-time assertions. A second version, accessed when using libraries from _DEBUGLIBPATH(), contains run-time assertions and trace points. The typical way to access the debug version is to set the **LD_LIBRARY_PATH** environment variable to _LDLIBPATH(). Debugging output is controlled using the following environment variables. These variables have no effect on the non-debug version of the library. + **VMMALLOC_LOG_LEVEL** The value of **VMMALLOC_LOG_LEVEL** enables trace points in the debug version of the library, as follows: + **0** - Tracing is disabled. This is the default level when **VMMALLOC_LOG_LEVEL** is not set. + **1** - Additional details on any errors detected are logged, in addition to returning the *errno*-based errors as usual. + **2** - A trace of basic operations is logged. + **3** - Enables a very verbose amount of function call tracing in the library. + **4** - Enables voluminous tracing information about all memory allocations and deallocations. Unless **VMMALLOC_LOG_FILE** is set, debugging output is written to *stderr*. + **VMMALLOC_LOG_FILE** Specifies the name of a file where all logging information should be written. If the last character in the name is "-", the *PID* of the current process will be appended to the file name when the log file is created. If **VMMALLOC_LOG_FILE** is not set, output is written to *stderr*. + **VMMALLOC_LOG_STATS** Setting **VMMALLOC_LOG_STATS** to 1 enables logging human-readable summary statistics at program termination. # NOTES # Unlike the normal **malloc**(3), which asks the system for additional memory when it runs out, **libvmmalloc** allocates the size it is told to and never attempts to grow or shrink that memory pool. # BUGS # **libvmmalloc** may not work properly with programs that perform **fork**(2) and do not call **exec**(3) immediately afterwards. See **ENVIRONMENT** for more details about experimental **fork**(2) support. If logging is enabled in the debug version of the library and the process performs **fork**(2), no new log file is created for the child process, even if the configured log file name ends with "-". All logging information from the child process will be written to the log file owned by the parent process, which may lead to corruption or partial loss of log data. Malloc hooks (see **malloc_hook**(3)), are not supported when using **libvmmalloc**. # ACKNOWLEDGEMENTS # **libvmmalloc** depends on jemalloc, written by Jason Evans, to do the heavy lifting of managing dynamic memory allocation. See: # SEE ALSO # **fork**(2), **dlclose(3)**, **exec**(3), **malloc**(3), **malloc_usable_size**(3), **posix_memalign**(3), **libpmem**(7), **libvmem**(7) and **** On Linux: **jemalloc**(3), **malloc_hook**(3), **pthreads**(7), **ld.so**(8) On FreeBSD: **ld.so**(1), **pthread**(3) pmdk-1.4.1/doc/macros.man000066400000000000000000000143011331545616200152030ustar00rootroot00000000000000# # Copyright 2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # These macros are defined for the m4 preprocessor and are controlled by # the FREEBSD, WIN32 and WEB variables. These MUST be explicitly defined or # undefined on the m4 command line. # # This solution allows the maintenance of Windows, Linux and FreeBSD # documentation in the same file. # # The macros are: # # _BSDWX(FreeBSD,WinLinux): # Choose text based on FREEBSD. Both arguments are optional # (although the comma must be present if FreeBSD is omitted). # Bracket string with (=q=, =e=) if it contains commas. # _DEBUGLIBPATH() # Inserts pathnames for debug libraries depending on WIN32 and # FREEBSD. # _LDLIBPATH() # Inserts suggested pathnames for LD_LIBRARY_PATH depending on # WIN32 and FREEBSD. # _MP(man_page_name, section): # Include the man page section number if not building for WEB. # _UNICODE(): # Inserts a standard note regarding UNICODE support if WIN32. # _U(func_name): # Append "U" to func_name if WIN32. # _UW(func_name): # Emit **func_nameU**()/**func_nameW**() if WIN32. # _UWFUNC(func_name, args): # Define U and W prototypes of char/wchar_t *func_name if WIN32. # Bracket args string with (=q=, =e=) if it is a comma-separated # list. # _UWFUNCR(ret_type, func_name, char_arg): # Define U and W prototypes of ret_type func_name if WIN32. # Single char/wchar_t argument is char_arg. # _UWFUNCRUW(ret_type, func_name, args): # Define U and W prototypes of ret_type[U/W] func_name if WIN32. # Bracket args string with (=q=, =e=) if it is a comma-separated # list. # _UWFUNCR1(ret_type, func_name, char_arg, rest_of_args, comment): # Define U and W prototypes of ret_type func_name if WIN32. # First char/wchar_t argument is char_arg. Bracket rest_of_args # string with (=q=, =e=) if it is a comma-separated list. # Comment is added after prototype definition if present. # _UWFUNCR12(ret_type, func_name, char_arg1, char_arg2, rest_of_args, # comment): # Define U and W prototypes of ret_type func_name if WIN32. # Two char/wchar_t arguments are char_arg1-2. Bracket # rest_of_args string with (=q=, =e=) if it is a comma-separated # list. Comment is added after prototype definition if present. # _UWFUNCR1UW(ret_type, func_name, arg1_type, arg1, rest_of_args): # Define U and W prototypes of ret_type func_name, append [U/W] # to arg1_type arg1. Bracket rest_of_args string with (=q=, =e=) # if it is a comma-separated list. # _UWFUNCR2(ret_type, func_name, arg1, char_arg, rest_of_args, comment): # Define U and W prototypes of ret_type func_name if WIN32. # Second char/wchar_t argument is char_arg. Bracket rest_of_args # string with (=q=, =e=) if it is a comma-separated list. # Comment is added after prototype definition if present. # _UWS(struct_name): # Emit *struct struct_nameU*/*struct struct_nameW* if WIN32. # _WINUX(Windows,UX): # Choose text based on WIN32. Both arguments are optional # (although the comma must be present if Windows is omitted). # Bracket string with (=q=, =e=) if it contains commas. changequote(=q=,=e=) changecom() define(_BSDWX, ifdef(=q=FREEBSD=e=,$1,$2)) define(_DEBUGLIBPATH, ifdef(=q=WIN32=e=,**/pmdk/src/x64/Debug**, ifdef(=q=FREEBSD=e=,**/usr/local/lib/pmdk_debug**, **/usr/lib/pmdk_debug**))) define(_LDLIBPATH, ifdef(=q=WIN32=e=,**/pmdk/src/x64/Debug**, ifdef(=q=FREEBSD=e=,**/usr/local/lib/pmdk_debug**, =q==q==q=**/usr/lib/pmdk_debug** or **/usr/lib64/pmdk_debug**, as appropriate=e==e==e=))) define(_MP, ifdef(=q=WEB=e=,$1,$1($2))) define(_UNICODE, ifdef(=q=WIN32=e=,=q==q= >NOTE: The PMDK API supports UNICODE. If the **PMDK_UTF8_API** macro is defined, basic API functions are expanded to the UTF-8 API with postfix *U*. Otherwise they are expanded to the UNICODE API with postfix *W*.=e==e=)) define(_U, ifdef(=q=WIN32=e=,$1U,$1)) define(_UW, ifdef(=q=WIN32=e=,**$1U**()/**$1W**(),**$1**())) define(_UWFUNC, ifdef(=q=WIN32=e=, const char *$1U($2); const wchar_t *$1W($2);, const char *$1($2);)) define(_UWFUNCR, ifdef(=q=WIN32=e=, $1 $2U(const char $3); $1 $2W(const wchar_t $3);, $1 $2(const char $3);)) define(_UWFUNCRUW, ifdef(=q=WIN32=e=, $1U $2U($3); $1W $2W($3);, $1 $2($3);)) define(_UWFUNCR1, ifdef(=q=WIN32=e=, $1 $2U(const char $3, $4);$5 $1 $2W(const wchar_t $3, $4);$5, $1 $2(const char $3, $4);$5)) define(_UWFUNCR12, ifdef(=q=WIN32=e=, $1 $2U(const char $3, const char $4, $5);$6 $1 $2W(const wchar_t $3, const wchar_t $4, $5);$6, $1 $2(const char $3, const char $4, $5);$6)) define(_UWFUNCR1UW, ifdef(=q=WIN32=e=, $1 $2U($3U $4, $5); $1 $2W($3W $4, $5);, $1 $2($3 $4, $5);)) define(_UWFUNCR2, ifdef(=q=WIN32=e=, $1 $2U($3, const char $4, $5);$6 $1 $2W($3, const wchar_t $4, $5);$6, $1 $2($3, const char $4, $5);$6)) define(_UWS, ifdef(=q=WIN32=e=,*struct $1U*/*struct $1W*,*struct $1*)) define(_WINUX, ifdef(=q=WIN32=e=,$1,$2)) pmdk-1.4.1/doc/pmempool/000077500000000000000000000000001331545616200150535ustar00rootroot00000000000000pmdk-1.4.1/doc/pmempool/pmempool-check.1.md000066400000000000000000000104011331545616200204330ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-CHECK, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-check.1 -- man page for pmempool-check) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **pmempool-check** -- check and repair persistent memory pool # SYNOPSIS # ``` $ pmempool check [] ``` # DESCRIPTION # The **pmempool** invoked with *check* command checks consistency of a given pool file. If the pool file is consistent **pmempool** exits with 0 value. If the pool file is not consistent non-zero error code is returned. In case of any errors, the proper message is printed. The verbosity level may be increased using **-v** option. The output messages may be also suppressed using **-q** option. It is possible to try to fix encountered problems using **-r** option. In order to be sure this will not corrupt your data you can either create backup of the pool file using **-b** option or just print what would be fixed without modifying original pool using **-N** option. > NOTE: Currently, checking the consistency of a *pmemobj* pool is **not** supported. ##### Available options: ##### `-r, --repair` Try to repair a pool file if possible. `-y, --yes` Answer yes on all questions. `-N, --no-exec` Don't execute, just show what would be done. Not supported on Device DAX. `-b, --backup ` Create backup of a pool file before executing. Terminate if it is *not* possible to create a backup file. This option requires **-r** option. `-a, --advanced` Perform advanced repairs. This option enables more aggressive steps in attempts to repair a pool. This option requires `-r, --repair`. `-q, --quiet` Be quiet and don't print any messages. `-v, --verbose` Be more verbose. `-h, --help` Display help message and exit. # EXAMPLE # ``` $ pmempool check pool.bin ``` Check consistency of "pool.bin" pool file ``` $ pmempool check --repair --backup pool.bin.backup pool.bin ``` Check consistency of "pool.bin" pool file, create backup and repair if necessary. ``` $ pmempool check -rvN pool.bin ``` Check consistency of "pool.bin" pool file, print what would be repaired with increased verbosity level. # SEE ALSO # **pmempool**(1), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7), **libpmempool**(7) and **** pmdk-1.4.1/doc/pmempool/pmempool-convert.1.md000066400000000000000000000056221331545616200210470ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-CONVERT, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-convert.1 -- man page for pmempool-convert) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **pmempool-convert** - upgrade pool files layout version # SYNOPSIS # ``` $ pmempool convert ``` # DESCRIPTION # The **pmempool** invoked with the *convert* command performs a conversion of the specified pool to the newest layout supported by this tool. Currently only **libpmemobj**(7) pools are supported. It is advised to have a backup of the pool before conversion. >NOTE: The conversion process is not fail-safe - power interruption may damage the pool. # EXAMPLE # ``` $ pmempool convert pool.obj ``` Updates pool.obj to the latest layout version. # SEE ALSO # **pmempool**(1), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7), **libpmempool**(7) and **** pmdk-1.4.1/doc/pmempool/pmempool-create.1.md000066400000000000000000000130011331545616200206200ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-CREATE, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-create.1 -- man page for pmempool-create) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **pmempool-create** -- create a persistent memory pool # SYNOPSIS # ``` $ pmempool create [] [] [] ``` # DESCRIPTION # The **pmempool** invoked with *create* command creates a pool file of specified type. Depending on a pool type it is possible to provide more properties of pool. Valid pool types are: **blk**, **log** and **obj** which stands for *pmemblk*, *pmemlog* and *pmemobj* pools respectively. By default the pool file is created with *minimum* allowed size for specified pool type. The minimum sizes for **blk**, **log** and **obj** pool types are **PMEMBLK_MIN_POOL**, **PMEMLOG_MIN_POOL** and **PMEMOBJ_MIN_POOL** respectively. See **libpmemblk**(7), **libpmemlog**(7) and **libpmemobj**(7) for details. For *pmemblk* pool type block size *\* is a required argument. In order to set custom size of pool use **-s** option, or use **-M** option to create a pool of maximum available size on underlying file system. The *size* argument may be passed in format that permits only the upper-case character for byte - B as specified in IEC 80000-13, IEEE 1541 and the Metric Interchange Format. Standards accept SI units with obligatory B - kB, MB, GB, ... which means multiplier by 1000 and IEC units with optional "iB" - KiB, MiB, GiB, ..., K, M, G, ... - which means multiplier by 1024. ##### Available options: ##### `-s, --size ` Size of pool file. `-M, --max-size` Set size of pool to available space of underlying file system. `-m, --mode ` Set permissions to (the default is 0664) when creating the files. If the file already exist the permissions are not changed. `-i, --inherit ` Create a new pool of the same size and other properties as *\*. `-f, --force` Remove the pool before creating. `-v, --verbose` Increase verbosity level. `-h, --help` Display help message and exit. ##### Options for PMEMBLK: ##### By default when creating a pmem **blk** pool, the **BTT** layout is *not* written until the first *write operation* of block entry is performed. Using **-w** option you can force writing the **BTT** layout by writing zero data to specified block number. By default the *write operation* is performed to block number 0. Please refer to **libpmemblk**(7) for details. `-w, --write-layout` Force writing the **BTT** layout by performing *write operation* to block number zero. ##### Options for PMEMOBJ: ##### By default when creating a pmem **obj** pool, the layout name provided to the **libpmemobj** library is an empty string. Please refer to **libpmemobj**(7) for details. `-l, --layout ` Layout name of the **pmemobj** pool. # EXAMPLE # ``` $ pmempool create blk 512 pool.blk ``` Create a blk pool file of minimum allowed size and block size 512 bytes ``` $ pmempool create log -M pool.log ``` Create a log pool file of maximum allowed size ``` $ pmempool create blk --size=4G --write-layout 1K pool.blk ``` Create a blk pool file of size 4G, block size 1K and write the BTT layout ``` $ pmempool create --layout my_layout obj pool.obj ``` Create an obj pool file of minimum allowed size and layout "my_layout" ``` $ pmempool create --inherit=pool.log new_pool.log ``` Create a pool file based on pool.log file # SEE ALSO # **pmempool**(1), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/pmempool/pmempool-dump.1.md000066400000000000000000000104221331545616200203260ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-DUMP, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-dump.1 -- man page for pmempool-dump) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RANGE](#range)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **pmempool-dump** -- dump user data from persistent memory pool # SYNOPSIS # ``` $ pmempool dump [] ``` # DESCRIPTION # The **pmempool** invoked with *dump* command dumps user data from specified pool file. The output format may be either binary or hexadecimal. By default the output format is hexadecimal. By default data is dumped to standard output. It is possible to dump data to other file by specifying **-o** option. In this case data will be appended to this file. Using **-r** option you can specify number of blocks/bytes/data chunks using special text format. See **RANGE** section for details. ##### Available options: ##### `-b, --binary` Dump data in binary format. `-r, --range ` Range of pool file to dump. This may be number of blocks for **blk** pool type or either number of bytes or number of data chunks for **log** pool type. `-c, --chunk ` Size of chunk for **log** pool type. See **pmemlog_walk**(3) in **libpmemlog**(7) for details. `-o, --output ` Name of output file. `-h, --help` Display help message and exit. # RANGE # Using **-r**, **--range** option it is possible to dump only a range of user data. This section describes valid format of *\* string. You can specify multiple ranges separated by commas. `-` All blocks/bytes/data chunks from *\* to *\* will be dumped. `-` All blocks/bytes/data chunks up to *\* will be dumped. `-` All blocks/bytes/data chunks starting from *\* will be dumped. `` Only *\* block/byte/data chunk will be dumped. # EXAMPLE # ``` $ pmempool dump pool.bin ``` Dump user data from pool.bin file to standard output ``` $ pmempool dump -o output.bin -r1,10-100 pool_blk.bin ``` Dump block number 1 and blocks from 10 to 100 from pool_blk.bin containing pmem blk pool to output.bin file ``` $ pmempool dump -r 1K-2K pool.bin ``` Dump data form 1K to 2K from pool.bin file. # SEE ALSO # **pmempool**(1), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/pmempool/pmempool-info.1.md000066400000000000000000000330351331545616200203210ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-INFO, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-info.1 -- man page for pmempool-info) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[RANGE](#range)
[STATISTICS](#statistics)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **pmempool-info** -- show information about persistent memory pool # SYNOPSIS # ``` $ pmempool info [] ``` # DESCRIPTION # The **pmempool** invoked with *info* command analyzes an existing pool created by **PMDK** libraries provided by **file** parameter. The **file** can be either existing pool file, a part file or a poolset file. The main task of this command is to print all usable information from pool headers and user data in human readable format. It automatically recognizes the pool type by parsing and analyzing the pool header. The recognition is done by checking the signature in the pool header. The main job of *info* command is to present internal data structures as they are stored in file but *not* for checking consistency. For this purpose there is the **pmempool-check**(1) command available. The **pmempool** with *info* command analyzes pool file as long as it is possible regarding *correctness* of internal meta-data (correct offsets, sizes etc.). If it is *not* possible to analyze the rest of the file, **pmempool** exits with error code and prints appropriate error message. Currently there is lack of interprocess synchronization for pool files, so the *info* command should be invoked off-line. Using **pmempool** on pool file which may be modified by another process may lead to unexpected errors in pool file. A poolset file passed to **pmempool info** may contain multiple replicas, also remote ones, but **pmempool** currently does not read any data from remote replicas. It prints only a remote node address and a remote replica descriptor. **pmempool info** opens pool file in *read-only* mode so the file will remain untouched after processing. The *info* command may collect and print basic statistics about data usage. The statistics are specific to the type of pool. See **STATISTICS** section for details. Although the pool consistency is *not* checked by the *info* command, it prints information about checksum errors and/or offsets errors. ##### Common options: ##### By default the *info* command of **pmempool** prints information about the most important internal data structures from pool. The particular set of headers and meta-data depend on pool type. The pool type is recognized automatically and appropriate information is displayed in human-readable format. To force processing specified file(s) as desired pool type use **-f** option with appropriate name of pool type. The valid names off pool types are **blk**, **log**, **obj** or **btt**. This option may be useful when the pool header is corrupted and automatic recognition of pool type fails. `-f, --force blk|log|obj|btt` Force parsing pool as specified pool type. >NOTE: By default only pool headers and internal meta-data are displayed. To display user data use **-d** option. Using **-r** option you can specify number of blocks/bytes/data chunks or objects using special text format. See **RANGE** section for details. The range refers to *block numbers* in case of pmem blk pool type, to *chunk numbers* in case of pmem log pool type and to *object numbers* in case of pmem obj pool type. See **EXAMPLES** section for an example of usage of these options. `-d, --data` Dump user data in hexadecimal format. In case of pmem *blk* pool type data is dumped in *blocks*. In case of pmem *log* pool type data is dumped as a wholeor in *chunks* if **-w** option is used (See **Options for PMEMLOG** section for details). `-r, --range ` Range of blocks/data chunks/objects/zone headers/chunk headers/lanes. See **RANGE** section for details about range format. `-n, --human` Print sizes in human-readable format with appropriate units (e.g. 4k, 8M, 16G) `-x, --headers-hex` Print pool's internal data in mixed format which consists of hexadecimal dump of header's data and parsed format displayed in human-readable format. This allows to see how data is stored in file. `-s, --stats` Print pool's statistics. See **STATISTICS** section for details. `-h, --help` Display help message and exit. ##### Options for PMEMLOG: ##### `-w, --walk ` Use this option to walk through used data with fixed data chunk size. See **pmemlog_walk**(3) in **libpmemlog**(7) for details. ##### Options for PMEMBLK: ##### By default the *info* command displays the **pmemblk** header and BTT (Block Translation Table) Info header in case of **pmemblk** pool type. To display BTT Map and/or BTT FLOG (Free List and Log) use **-m** and **-g** options respectively or increase verbosity level. In order to display BTT Info header backup use **-B** option. `-m, --map` Print BTT Map entries. `-g, --flog` Print BTT FLOG entries. `-B, --backup` Print BTT Info header backup. >NOTE: By default the *info* command displays all data blocks when **-d** options is used. However it is possible to skip blocks marked with *zero* and/or *error* flags. It is also possible to skip blocks which are *not* marked with any flag. Skipping blocks has impact on blocks ranges (e.g. display 10 blocks marked with error flag in the range from 0 to 10000) and statistics. `-z, --skip-zeros` Skip blocks marked with *zero* flag. `-e, --skip-error` Skip blocks marked with *error* flag. `-u, --skip-no-flag` Skip blocks *not* marked with any flag. ##### Options for PMEMOBJ: ##### By default the *info* command displays pool header and **pmemobj** pool descriptor. In order to print information about other data structures one of the following options may be used. `-l, --lanes []` Print information about lanes. If range is not specified all lanes are displayed. The range can be specified using **-r** option right after the **-l** option. See **RANGE** section for details about range format. `-R, --recovery` Print information about only those lanes which require recovery process. This option requires **-l**, **--lanes** option. `-S, --section tx,allocator,list` Print information only about specified sections from lane. The section types may be separated by comma. This option requires **-l**, **--lanes** option. `-O, --object-store` Print information about all allocated objects. `-t, --types ` Print information about allocated objects only from specified range of type numbers. If **-s**, **--stats** option is specified the objects statistics refer to objects from specified range of type numbers. This option requires **-O**, **--object-store** or **-s**, **--stats** options. See **RANGE** section for details about range format. `-E, --no-empty` Ignore empty lists of objects. This option requires **-O**, **--object-store** option. `-o, --root` Print information about a root object. `-A, --alloc-header` Print object's allocation header. This option requires **-O**, **--object-store** or **-l**, **--lanes** or **-o**, **--root** options. `-a, --oob-header` Print object's out of band header. This option requires **-O**, **--object-store** or **-l**, **--lanes** or **-o**, **--root** options. `-H, --heap` Print information about **pmemobj** heap. By default only a heap header is displayed. `-Z, --zones` If the **-H**, **--heap** option is used, print information about zones from specified range. If the **-O**, **--object-store** option is used, print information about objects only from specified range of zones. This option requires **-O**, **--object-store**, **-H**, **--heap** or **-s**, **--stats** options. The range can be specified using **-r** option right after the **-Z** option. See **RANGE** section for details about range format. `-C, --chunks []` If the **-H, --heap** option is used, print information about chunks from specified range. By default information about chunks of types *used* , *free* and *run* are displayed. If the **-O, --object-store** option is used, print information about objects from specified range of chunks within a zone. This option requires **-O, --object-store**, **-H, --heap** or **-s, --stats** options. The range can be specified using **-r** option right after the **-C** option. See **RANGE** section for details about range format. `-T, --chunk-type used,free,run,footer` Print only specified type(s) of chunks. The multiple types may be specified separated by comma. This option requires **-H, --heap** and **-C, --chunks** options. `-b, --bitmap` Print bitmap of used blocks in chunks of type run. This option requires **-H, --heap** and **-C, --chunks** options. `-p, --replica ` Print information from *\* replica. The 0 value means the master pool file. # RANGE # Using **-r, --range** option it is possible to dump only a range of user data. This section describes valid format of *\* string. You can specify multiple ranges separated by commas. `-` All blocks/bytes/data chunks from *\* to *\* will be dumped. `-` All blocks/bytes/data chunks up to *\* will be dumped. `-` All blocks/bytes/data chunks starting from *\* will be dumped. `` Only *\* block/byte/data chunk will be dumped. # STATISTICS # Below is the description of statistical measures for specific pool types. ##### PMEMLOG ##### + **Total** - Total space in pool. + **Available** - Size and percentage of available space. + **Used** - Size and percentage of used space. ##### PMEMBLK ##### + **Total blocks** - Total number of blocks in pool. + **Zeroed blocks** - Number and percentage of blocks marked with *zero* flag. + **Error blocks** - Number and percentage of blocks marked with *error* flag. + **Blocks without any flag** - Number and percentage of blocks *not* marked with any flag. >NOTE: In case of pmemblk, statistics are evaluated for blocks which meet requirements regarding: *range* of blocks (**-r** option), *skipped* types of blocks (**-z**, **-e**, **-u** options). ##### PMEMOBJ ##### + **Object store** + **Number of objects** - Total number of objects and number of objects per type number. + **Number of bytes** - Total number of bytes and number of bytes per type number. + **Heap** + **Number of zones** - Total number of zones in the pool. + **Number of used zones** - Number of used zones in the pool. + **Zone** The zone's statistics are presented for each zone separately and the aggregated results from all zones. + **Number of chunks** - Total number of chunks in the zone and number of chunks of specified type. + **Chunks size** - Total size of all chunks in the zone and sum of sizes of chunks of specified type. + **Allocation classes** + **Units** - Total number of units of specified class. + **Used units** - Number of used units of specified class. + **Bytes** - Total number of bytes of specified class. + **Used bytes** - Number of used bytes of specified class. + **Total bytes** - Total number of bytes of all classes. + **Total used bytes** - Total number of used bytes of all classes. # EXAMPLE # ``` $ pmempool info ./pmemblk ``` Parse and print information about "pmemblk" pool file. ``` $ pmempool info -f blk ./pmempool ``` Force parsing "pmempool" file as **pmemblk** pool type. ``` $ pmempool info -d ./pmemlog ``` Print information and data in hexadecimal dump format for file "pmemlog". ``` $ pmempool info -d -r10-100 -eu ./pmemblk ``` Print information from "pmemblk" file. Dump data blocks from 10 to 100, skip blocks marked with error flag and not marked with any flag. # SEE ALSO # **pmempool**(1), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/pmempool/pmempool-rm.1.md000066400000000000000000000105161331545616200200030ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-RM, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-rm.1 -- man page for pmempool-rm) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLE](#example)
[SEE ALSO](#see-also)
# NAME # **pmempool-rm** -- remove a persistent memory pool # SYNOPSIS # ``` $ pmempool rm [] .. ``` # DESCRIPTION # The **pmempool rm** command removes each specified file. If the specified file is a pool set file, all pool files (single-file pool or part files) and remote replicas are removed. By default the **pmempool rm** does not remove pool set files. All local and remote pool files are removed using **unlink**(3) call, except the pools created on **device dax** which are zeroed instead. If specified file does not exist, the remote pool is broken or not accessible, the **pmempool rm** command terminates with an error code. By default it prompts before removing *write-protected* local files. See **REMOTE REPLICATION** section for more details about support for remote pools. See **EXAMPLES** section for example usage of the *rm* command. ##### Available options: ##### `-h, --help` Print help message `-v, --verbose` Be verbose and print all removing files. `-s, --only-pools` Remove only pool files and do not remove pool set files (default behaviour). `-a, --all` Remove all pool set files - local and remote. `-l, --local` Remove local pool set files. `-r, --remote` Remove remote pool set files. `-f, --force` Remove all specified files, ignore nonexistent files, never prompt. `-i, --interactive` Prompt before removing every single file or remote pool. # REMOTE REPLICATION # A remote pool is removed using **rpmem_remove**(3) function if **librpmem**(7) library is available. If a pool set file contains remote replication but **librpmem**(7) is not available, the **pmempool rm** command terminates with an error code, unless the **-f, --force** option is specified. # EXAMPLE # ``` $ pmempool rm pool.obj pool.blk ``` Remove specified pool files. ``` $ pmempool rm pool.set ``` Remove all pool files from the "pool.set", do not remove *pool.set* itself. ``` $ pmempool rm -a pool.set ``` Remove all pool files from the "pool.set", remove the local pool set file and all remote pool set files. # SEE ALSO # **pmempool**(1), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7), **librpmem**(7) and **** pmdk-1.4.1/doc/pmempool/pmempool-sync.1.md000066400000000000000000000071131331545616200203400ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-SYNC, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-sync.1 -- man page for pmempool-sync) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLES](#examples)
[SEE ALSO](#see-also)
# NAME # **pmempool-sync** -- Synchronize replicas or their parts within a pool set. # SYNOPSIS # ``` pmempool sync [options] ``` NOTE: Only the pool set file used to create the pool should be used for syncing the pool. # DESCRIPTION # The **pmempool sync** command synchronizes data between replicas within a pool set. It checks if metadata of all replicas in a pool set are consistent, i.e. all parts are healthy, and if any of them is not, the corrupted or missing parts are recreated and filled with data from one of the healthy replicas. Currently synchronizing data is allowed only for **pmemobj** pools (see **libpmemobj**(7)). _WINUX(,=q=If a pool set has the option *SINGLEHDR* or *NOHDRS* (see **poolset**(5)), **pmempool sync** command has limited capability of checking its metadata. This is due to limited or no, respectively, internal metadata at the beginning of pool set parts in every replica when either of the options is used. In that cases, only missing parts or the ones which cannot be opened are recreated.=e=) ##### Available options: ##### `-d, --dry-run` : Enable dry run mode. In this mode no changes are applied, only check for viability of synchronization. `-v, --verbose` : Increase verbosity level. `-h, --help` : Display help message and exit. # SEE ALSO # **pmempool(1)**, **libpmemblk(7)**, **libpmemlog(7)**, **libpmempool(7)** and **** pmdk-1.4.1/doc/pmempool/pmempool-transform.1.md000066400000000000000000000152261331545616200214030ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL-TRANSFORM, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool-transform.1 -- man page for pmempool-transform) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[EXAMPLES](#examples)
[SEE ALSO](#see-also)
# NAME # **pmempool-transform** -- Modify internal structure of a pool set. # SYNOPSIS # ``` pmempool transform [options] ``` # DESCRIPTION # The **pmempool transform** command modifies internal structure of a pool set defined by the `poolset_file_src` file, according to a structure described in the `poolset_file_dst` file. The following operations are supported: * adding replicas - one or more new replicas can be added and synchronized with other replicas in the pool set, * removing replicas - one or more replicas can be removed from the pool set _WINUX(.,=q=, * adding or removing pool set options.=e=) Only one of the above operations can be performed at a time. Currently adding and removing replicas are allowed only for **pmemobj** pools (see **libpmemobj**(7)). The *poolset_file_src* argument provides the source pool set to be changed. The *poolset_file_dst* argument points to the target pool set. _WINUX(=q=When adding or deleting replicas, the two pool set files can differ only in the definitions of replicas which are to be added or deleted. One cannot add and remove replicas in the same step. Only one of these operations can be performed at a time. Reordering replicas is not supported Also, to add a replica it is necessary for its effective size to match or exceed the pool size. Otherwise the whole operation fails and no changes are applied. Effective size of a replica is the sum of sizes of all its part files decreased by 4096 bytes per each part file. The 4096 bytes of each part file is utilized for storing internal metadata of the pool part files.=e=) _WINUX(,=q=When adding or deleting replicas, the two pool set files can differ only in the definitions of replicas which are to be added or deleted. When adding or removing pool set options (see **poolset**(5)), the rest of both pool set files have to be of the same structure. The operation of adding/removing a pool set option can be performed on a pool set with local replicas only. To add/remove a pool set option to/from a pool set with remote replicas, one has to remove the remote replicas first, then add/remove the option, and finally recreate the remote replicas having added/removed the pool set option to/from the remote replicas' poolset files. To add a replica it is necessary for its effective size to match or exceed the pool size. Otherwise the whole operation fails and no changes are applied. If none of the poolset options is used, the effective size of a replica is the sum of sizes of all its part files decreased by 4096 bytes per each part file. The 4096 bytes of each part file is utilized for storing internal metadata of the pool part files. If the option *SINGLEHDR* is used, the effective size of a replica is the sum of sizes of all its part files decreased once by 4096 bytes. In this case only the first part contains internal metadata. If the option *NOHDRS* is used, the effective size of a replica is the sum of sizes of all its part files. In this case none of the parts contains internal metadata.=e=) ##### Available options: ##### `-d, --dry-run` : Enable dry run mode. In this mode no changes are applied, only check for viability of the operation is performed. `-v, --verbose` : Increase verbosity level. `-h, --help` : Display help message and exit. # EXAMPLES # ##### Example 1. ##### Let files `/path/poolset_file_src` and `/path/poolset_file_dst` have the following contents: ``` PMEMPOOLSET 20M /0/partfile1 20M /0/partfile2 25M /0/partfile3 REPLICA 40M /1/partfile1 20M /1/partfile2 ``` ``` PMEMPOOLSET 20M /0/partfile1 20M /0/partfile2 25M /0/partfile3 REPLICA 40M /1/partfile1 20M /1/partfile2 REPLICA 50M /2/partfile1 20M /2/partfile2 ``` Then, the command `pmempool transform /path/poolset_file_src /path/poolset_file_dst` adds a replica to the pool set. All other replicas remain unchanged and the size of the pool remains 60M. ##### Example 2. ##### Let files `/path/poolset_file_src` and `/path/poolset_file_dst` have the following contents: ``` PMEMPOOLSET 20M /0/partfile1 20M /0/partfile2 25M /0/partfile3 REPLICA 40M /1/partfile1 20M /1/partfile2 ``` ``` PMEMPOOLSET 20M /0/partfile1 20M /0/partfile2 25M /0/partfile3 ``` Then `pmempool_transform /path/poolset_file_src /path/poolset_file_dst` deletes the second replica from the pool set. The first replica remains unchanged and the size of the pool is still 60M. # SEE ALSO # **pmempool(1)**, **libpmemblk(7)**, **libpmemlog(7)**, **libpmempool(7)** and **** pmdk-1.4.1/doc/pmempool/pmempool.1.md000066400000000000000000000102311331545616200173610ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(PMEMPOOL, 1) collection: pmempool header: PMDK date: pmem Tools version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (pmempool.1 -- man page for pmempool) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[OPTIONS](#options)
[COMMANDS](#commands)
[SEE ALSO](#see-also)
# NAME # **pmempool** -- Persistent Memory Pool Management Tool # SYNOPSIS # ``` $ pmempool [--help] [--version] [] ``` # DESCRIPTION # The **pmempool** is a management tool for *Persistent Memory* pool files created by **PMDK** libraries. The main purpose of **pmempool** is to provide a user with a set of utilities for off-line analysis and manipulation of pools created by pmem libraries. The pmempool is a generic command which consists of subcommands for specific purposes. Some of subcommands are required to work *without* any impact on processed pool, but some of them *may* create a new or modify an existing one. The **pmempool** may be useful for troubleshooting by system administrators and for software developers who work on applications based on **PMDK**. The latter may find these tools useful for testing and debugging purposes also. # OPTIONS # `-V, --version` Prints the version of **pmempool**. `-h, --help` Prints synopsis and list of commands. # COMMANDS # Currently there is a following set of commands available: + **pmempool-info**(1) - Prints information and statistics in human-readable format about specified pool. + **pmempool-check**(1) - Checks pool's consistency and repairs pool if it is not consistent. + **pmempool-create**(1) - Creates a pool of specified type with additional properties specific for this type of pool. + **pmempool-dump**(1) - Dumps usable data from pool in hexadecimal or binary format. + **pmempool-rm**(1) Removes pool file or all pool files listed in pool set configuration file. + **pmempool-convert**(1) - Updates the pool to the latest available layout version. + **pmempool-sync**(1) - Synchronizes replicas within a poolset. + **pmempool-transform**(1) - Modifies internal structure of a poolset. In order to get more information about specific *command* you can use **pmempool help .** # SEE ALSO # **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/poolset/000077500000000000000000000000001331545616200147105ustar00rootroot00000000000000pmdk-1.4.1/doc/poolset/poolset.5.md000066400000000000000000000273401331545616200170700ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(POOLSET, 5) collection: poolset header: PMDK date: poolset API version 1.0 ... [comment]: <> (Copyright 2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (poolset.5 -- man page that describes format of pool set file) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[REPLICAS](#replicas)
[POOL SET OPTIONS](#pool-set-options)
[NOTES](#notes)
[SEE ALSO](#see-also)
# NAME # poolset -- persistent memory pool configuration file format # SYNOPSIS # ```c mypool.set ``` # DESCRIPTION # Depending on the configuration of the system, the available non-volatile memory space may be divided into multiple memory devices. In such case, the maximum size of the transactional object store could be limited by the capacity of a single memory device. Therefore, **libpmemobj**(7), **libpmemblk**(7) and **libpmemlog**(7) allow building object stores spanning multiple memory devices by creation of persistent memory pools consisting of multiple files, where each part of such a *pool set* may be stored on a different pmem-aware filesystem. To improve reliability and eliminate single point of failure, **libpmemobj**(7) also allows all the data written to a persistent memory pool to be copied to local _WINUX(,or remote) pool *replicas*, thereby providing backup for the persistent memory pool by producing a *mirrored pool set*. In practice, the pool replicas may be considered as binary copies of the "master" pool set. Data replication is not supported in **libpmemblk**(7) and **libpmemlog**(7). The *set* file for each type of pool is a plain text file. Lines in the file are formatted as follows: + The first line of the file must be the literal string "PMEMPOOLSET" + The pool parts are specified, one per line, in the format: *size* *pathname* + *Replica* sections, if any, start with the literal string "REPLICA". See **REPLICAS**, below, for further details. + Pool set options, if any, start with literal string *OPTION*. See **POOL SET OPTIONS** below for details. + Lines starting with "#" are considered comments and are ignored. The *size* must be compliant with the format specified in IEC 80000-13, IEEE 1541 or the Metric Interchange Format. These standards accept SI units with obligatory B - kB, MB, GB, ... (multiplier by 1000) suffixes, and IEC units with optional "iB" - KiB, MiB, GiB, ..., K, M, G, ... - (multiplier by 1024) suffixes. *pathname* must be an absolute pathname. The *pathname* of a part can point to a Device DAX. Device DAX is the device-centric analogue of Filesystem DAX. It allows memory ranges to be allocated and mapped without need of an intervening file system. Pools created on Device DAX have additional options and restrictions: + The *size* may be set to "AUTO", in which case the size of the device will be automatically resolved at pool creation time. + To concatenate more than one Device DAX device into a single pool set, the configured internal alignment of the devices must be 4KiB, unless the *SINGLEHDR* or *NOHDRS* option is used in the pool set file. See **POOL SET OPTIONS** below for details. Please see **ndctl-create-namespace**(1) for more information on Device DAX, including how to configure desired alignment. The minimum file size of each part of the pool set is defined as follows: + For block pools, as **PMEMBLK_MIN_PART** in **\** + For object pools, as **PMEMOBJ_MIN_PART** in **\** + For log pools, as **PMEMLOG_MIN_PART** in **\** The net pool size of the pool set is equal to: ``` net_pool_size = sum_over_all_parts(page_aligned_part_size - 4KiB) + 4KiB ``` where ``` page_aligned_part_size = part_size & ~(page_size - 1) ``` Note that page size is OS specific. For more information please see **sysconf**(3). The minimum net pool size of a pool set is defined as follows: + For block pools, as **PMEMBLK_MIN_POOL** in **\** + For object pools, as **PMEMOBJ_MIN_POOL** in **\** + For log pools, as **PMEMLOG_MIN_POOL** in **\** Here is an example "mypool.set" file: ``` PMEMPOOLSET OPTION NOHDRS 100G /mountpoint0/myfile.part0 200G /mountpoint1/myfile.part1 400G /mountpoint2/myfile.part2 ``` The files in the set may be created by running one of the following commands. To create a block pool: ``` $ pmempool create blk mypool.set ``` To create a log pool: ``` $ pmempool create log mypool.set ``` # REPLICAS # Sections defining replica sets are optional. There may be multiple replica sections. Local replica sections begin with a line containing only the literal string "REPLICA", followed by one or more pool part lines as described above. _WINUX(, =q=Remote replica sections consist of the *REPLICA* keyword, followed on the same line by the address of a remote host and a relative path to a remote pool set file: ``` REPLICA [@] [/] ``` + *hostname* must be in the format recognized by the **ssh**(1) remote login client + *pathname* is relative to the root config directory on the target node - see **librpmem**(3) There are no other lines in the remote replica section - the REPLICA line defines a remote replica entirely. =e=) Here is an example "myobjpool.set" file with replicas: ``` PMEMPOOLSET 100G /mountpoint0/myfile.part0 200G /mountpoint1/myfile.part1 400G /mountpoint2/myfile.part2 # local replica REPLICA 500G /mountpoint3/mymirror.part0 200G /mountpoint4/mymirror.part1 _WINUX(,=q= # remote replica REPLICA user@example.com remote-objpool.set=e=) ``` The files in the object pool set may be created by running the following command: ``` $ pmempool create --layout="mylayout" obj myobjpool.set ``` _WINUX(, =q=Remote replica cannot have replicas, i.e. a remote pool set file cannot define any replicas.=e=) # POOL SET OPTIONS # Pool set options can appear anywhere after the line with *PMEMPOOLSET* string. Pool set file can contain several pool set options. The following options are supported: + *SINGLEHDR* + *NOHDRS* If the *SINGLEHDR* option is used, only the first part in each replica contains the pool part internal metadata. In that case the effective size of a replica is the sum of sizes of all its part files decreased once by 4096 bytes. The *NOHDRS* option can appear only in the remote pool set file, when **librpmem** does not serve as a means of replication for **libpmemobj** pool. In that case none of the pool parts contains internal metadata. The effective size of such a replica is the sum of sizes of all its part files. Options *SINGLEHDR* and *NOHDRS* are mutually exclusive. If both are specified in a pool set file, creating or opening the pool will fail with an error. When using the *SINGLEHDR* or *NOHDRS* option, one can concatenate more than one Device DAX devices with any internal alignments in one replica. The *SINGLEHDR* option concerns only replicas that are local to the pool set file. That is if one wants to create a pool set with the *SINGLEHDR* option and with remote replicas, one has to add this option to the local pool set file as well as to every single remote pool set file. Using the *SINGLEHDR* and *NOHDRS* options has important implications for data integrity checking and recoverability in case of a pool set damage. See _UW(pmempool_sync) API for more information about pool set recovery. # DIRECTORIES # Providing a directory as a part's *pathname* allows the pool to dynamically create files and consequently removes the user-imposed limit on the size of the pool. The *size* argument of a part in a directory poolset becomes the size of the address space reservation required for the pool. In other words, the size argument is the maximum theoretical size of the mapping. This value can be freely increased between instances of the application, but decreasing it below the real required space will result in an error when attempting to open the pool. The directory must NOT contain user created files with extension *.pmem*, otherwise the behavior is undefined. If a file created by the library within the directory is in any way altered (resized, renamed) the behavior is undefined. A directory poolset must exclusively use directories to specify paths - combining files and directories will result in an error. A single replica can consist of one or more directories. If there are multiple directories, the address space reservation is equal to the sum of the sizes. The order in which the files are created is unspecified, but the library will try to maintain equal usage of the directories. By default pools grow in 128 megabyte increments. Only poolsets with the *SINGLEHDR* option can safely use directories. # NOTES # Creation of all the parts of the pool set and the associated replica sets can be done with the **pmemobj_create**(3), **pmemblk_create**(3) or **pmemlog_create**(3) function, or by using the **pmempool**(1) utility. Restoring data from a local _WINUX(,or remote) replica can be done by using the **pmempool-sync**(1) command or the _UW(pmempool_sync) API from the **libpmempool**(3) library. Modifications of a pool set file configuration can be done by using the **pmempool-transform**(1) command or the _UW(pmempool_transform) API from the **libpmempool**(3) library. When creating a pool set consisting of multiple files, or when creating a replicated pool set, the *path* argument passed to **pmemobj_create**(3), **pmemblk_create**(3) or **pmemlog_create**(3) must point to the special *set* file that defines the pool layout and the location of all the parts of the pool set. When opening a pool set consisting of multiple files, or when opening a replicated pool set, the *path* argument passed to **pmemobj_open**(3), **pmemblk_open**(3) or **pmemlog_open**(3) must point to the same *set* file that was used for pool set creation. # SEE ALSO # **ndctl-create-namespace**(1), **pmemblk_create**(3), **pmemlog_create**(3), **pmemobj_create**(3), **sysconf**(3), **libpmemblk**(7), **libpmemlog**(7), **libpmemobj**(7) and **** pmdk-1.4.1/doc/rpmemd/000077500000000000000000000000001331545616200145075ustar00rootroot00000000000000pmdk-1.4.1/doc/rpmemd/rpmemd.1.md000066400000000000000000000204261331545616200164600ustar00rootroot00000000000000--- layout: manual Content-Style: 'text/css' title: _MP(RPMEMD, 1) collection: rpmemd header: PMDK date: rpmemd version 1.4 ... [comment]: <> (Copyright 2016-2017, Intel Corporation) [comment]: <> (Redistribution and use in source and binary forms, with or without) [comment]: <> (modification, are permitted provided that the following conditions) [comment]: <> (are met:) [comment]: <> ( * Redistributions of source code must retain the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer.) [comment]: <> ( * Redistributions in binary form must reproduce the above copyright) [comment]: <> ( notice, this list of conditions and the following disclaimer in) [comment]: <> ( the documentation and/or other materials provided with the) [comment]: <> ( distribution.) [comment]: <> ( * Neither the name of the copyright holder nor the names of its) [comment]: <> ( contributors may be used to endorse or promote products derived) [comment]: <> ( from this software without specific prior written permission.) [comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS) [comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR) [comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT) [comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,) [comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT) [comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,) [comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY) [comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT) [comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE) [comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) [comment]: <> (rpmemd.1.md -- man page for rpmemd) [NAME](#name)
[SYNOPSIS](#synopsis)
[DESCRIPTION](#description)
[OPTIONS](#options)
[CONFIGURATION FILES](#configuration-files)
[EXAMPLE](#example)
[DEFAULT CONFIGURATION](#default-configuration)
[PERSISTENCY METHODS](#persistency-methods)
[SEE ALSO](#see-also)
# NAME # **rpmemd** -- librpmem target node process (EXPERIMENTAL) # SYNOPSIS # ``` $ rpmemd [--help] [--version] [] ``` # DESCRIPTION # The **rpmemd** process is executed on target node by **librpmem**(7) library over **ssh**(1) and facilitates access to persistent memory over RDMA. The **rpmemd** should not be run manually under normal conditions. # OPTIONS # Command line options overwrite the default **rpmemd** configuration, the global configuration file and the user configuration file. `-V, --version` Displays **rpmemd** version and exits. `-h, --help` Prints synopsis and list of parameters and exits. `-c, --config ` Custom configuration file location. If the custom configuration file is provided others are omitted. See **CONFIGURATION FILES** section for details. All options described in **CONFIGURATION FILES** section are common for both the configuration file and the command line - the equivalent of the following line in the config file: `option = value` is `--option value` in the command line. The following command line options: **--persist-apm**, **--persist-general** and **--use-syslog** should not be followed by any value. Presence of each of them in the command line turns on an appropriate option. See **CONFIGURATION FILES** section for details. `-r, --remove ` Remove a pool described by given pool set file descriptor. It is interpreted as a path to the pool set file relative to the pool set directory. `-f, --force` Ignore errors when removing a pool file using **--remove** option. # CONFIGURATION FILES # The **rpmemd** searches for the configuration files with following priorities: + The global configuration file located in **/etc/rpmemd/rpmemd.conf**. + The user configuration file located in the user home directory (**$HOME/.rpmemd.conf**). The **rpmemd** can also read configuration from the custom configuration file provided using **--config** command line option. See **OPTIONS** section for details. The default configuration is described in the **DEFAULT CONFIGURATION** section. The configuration file is a plain text file. Each line of the configuration file can store only one configuration option defined as a *key=value* pair. Empty lines and lines starting with *#* are omitted. The allowed options are: + `log-file = ` - log file location + `poolset-dir = ` - pool set files directory + `persist-apm = {yes|no}` - enable **The Appliance Persistency Method**. This option must be set only if the target platform has non-allocating writes IO enabled. See **PERSISTENCY METHODS** section for details. + `persist-general = {yes|no}` - enable **The General Purpose Server Persistency Method**. See **PERSISTENCY METHODS** section for details. + `use-syslog = {yes|no}` - use **syslog**(3) for logging messages instead of log file + `log-level = ` - set log level value. Accepted *\* values are: + **err** - error conditions + **warn** - warning conditions + **notice** - normal, but significant conditions + **info** - informational message + **debug** - debug-level message The **$HOME** sub-string in the *poolset-dir* path is replaced with the current user home directory. # EXAMPLE # Example of the configuration file: ``` # This is an example of configuration file log-file = $HOME/.logs/rpmemd.log poolset-dir = $HOME/poolsets/ persist-apm = yes persist-general = no use-syslog = no # Use log file instead of syslog log-level = info ``` # DEFAULT CONFIGURATION # The **rpmemd** default configuration is equivalent of the following configuration file: ``` log-file = /var/log/rpmemd.log poolset-dir = $HOME persist-apm = no persist-general = yes use-syslog = yes log-level = err ``` # PERSISTENCY METHODS # The **librpmem**(7) supports two methods for making data written to remote persistent memory durable. The difference between the use of the two mechanisms is based on whether **librpmem**(7) will make use of non-allocating writes on the remote node. + **The General Purpose Server Persistency Method** does not have any requirements for the platform on which the target daemon runs and can be enabled by administrator using the *persist-general* option. This method utilize **libpmem**(7) persistency mechanisms on remote node and requires additional communication between initiator and remote node using the in-band connection. + **The Appliance Persistency Method** requires non-allocating writes enabled on the platform and can be enabled by administrator using *persist-apm* option. This method requires to issue an RDMA READ operation after the RDMA WRITE operations performed on requested chunk of memory. "Non-allocating write requests" is the Intel Integrated IO Controller mode where all incoming PCIe writes will utilize non-allocating buffers for the write requests. Non-allocating writes are guaranteed to bypass all of the CPU caches and force the write requests to flow directly to the Integrated Memory Controller without delay. The **rpmemd** dynamically choose the appropriate persistency method and the flushing to persistence primitive for GPSPM for each opened pool set name depending on available persistency methods and whether all pool set parts are stored in the persistent memory. If the **Appliance Persistency Method** is enabled and the pool set is stored in the persistent memory **rpmemd** will use the **Appliance Persistency Method**. If the pool set is NOT stored in the persistent memory it will fallback to the **General Puropose Server Persistency Method** with **pmem_msync**(3). If the **General Puropose Server Persistency Method** is enabled and the pool set is stored in the persistent memory **rpmemd** will use **pmem_persist**(3). If the pool set is NOT stored in the persistent momory it will use **pmem_msync**(3). See **pmem_persist**(3) and **pmem_msync**(3) for more details. # SEE ALSO # **ssh**(1), **pmem_msync**(3), **pmem_persist**(3), **syslog**(3), **libpmem**(7), **libpmemobj**(7), **librpmem**(7) and **** pmdk-1.4.1/res/000077500000000000000000000000001331545616200132475ustar00rootroot00000000000000pmdk-1.4.1/res/PMDK.ico000066400000000000000000001475131331545616200145110ustar00rootroot000000000000002V(L2 h@@ (B#PNG  IHDR\rf2\IDATx]|~:hFA*"{ァV(ZP-C, pb/XVVn͑KK%wݽ^'eX9m5 8]Ɲ'tDĠ9Cێ3 3,?jY`5Y0bĨ"r3nyڢWS[$gr]O(z"FYq&D g#ObD)&L".C  cy,7{2&Cмwc 8w[%Ú ̆q,%#Fqp9#A\7Amh>Gh&b|n V,.D=)wd `HՋʣUBjw!ch(t:o\.'_YVXn2q?cl \h_\qO }0@,!Φi#LpOj#&LN]kݼlFZ qdd#FQϓ"w=4Og @p ڿY_w~D̶VUpMXbq0u.C8 "`\L-bMMJ; 1+oC@LCک؈@ <䤏@0P @@ |(ad #SV0[ @xIl8"#f:F/fY k`#F/]#F7Gxg_BbĈ4Ձ`N {x@\`w 7n!03owp_&ϳ95`W@G@xXn? =:{=3@0P @@ |(a > ‡aj%S<@p> srLKp&Q#JV( E//!9 w`[ %1?|q17!] )`1gg`tAdל!* ."FcFR"l\j4 j?5tx Ĩ}s/61`_-0+V[ZmMԃ;E~|(g4fD菠9[͡ǻ`v'Ε{a <8:}]?~mL{\nґ$6/³ _H0;~xkM`PI={`@ Np@BwpB+"܃qW[;)| ,1]eoOAp @hj^ &GJV 0 0@H?4 L&񑐘B@#߅&=jr=(nF9!,zٶDm3GE&7fѝY[;dZDN;'}n%h*8y u3[UY&Rsu-!\mVv.w3_pòSTUکa=u V\_O!ǝ״w}=JUw`VEpr}!-5-sT`K*>pV_%i^qPY[= Z nBM~ ׁHer0̺[aﶣc!qRFI;ֵC{:9} pxlyOB" ވ~s/oxI䉠9 JPzaݯ˨\,> {4 ,?! bWj[QIq8la,hcvո/`I6jo>9]wT8uCr%!Awo pp< `6*u <}\=S|</9iT|ƿ:ΕCq>KD?h&o6#L-N Mׅ\yseKsFz\<;DGls\-@#83ZRV;ꁙ_OzOgz' {օߖ}ywo{Qq$ FhX\weNBz8 ]W'q4jw^1]za+["H \ Lz?)#jNv **hd%Sآ9C_7.Σ8Z_7rU=d Ty]4x>u04t}~y)W*|pE6Bu"Y_2Đƞ2$wŠдO}(V&{YϏ!%%Y}U.I1!RcK5)xOw {)[ttBւ>}Y=Ry\愁ow9}^ȯwR HjJJ"-j@GTO>rAptg3z2YG@¿9нMǓ և Q#'7Et^yeN @/C]lO A 0%;.@ /:F=oeއ{N"xdTN9_$/$'@ܟw}$x7Erڍ8_>^P9+E{a-t'qY`?3fG/+/9kR&ye䄮[CpYڄZjTۧT}Nm3r'I?@9@l݁3Aidd]ݐnIEAz)2)_&m /ZNuwRP~1HT48I-->Ng}b[8uA,'rcrj;r8ٛԖJ=O~ qG4>J ph "b*PrpMb;մX 35B1[`It65?(ٿ$J,]tߊRxxwC}rM)V rE\Voe!MYeU9kߡYpr@șh.TU`Bv^m9m 0rM(P0?lz{"ˆDۗP[kelT++Ǭ+]xS[`ifawU$7fClMv<^+^=hv5f:9iI+9שTbE,}$cQ/ X6nnWUGh=Cg)-:3:-w?Rlo?.g[p}4 ̽e! >.MZ$sSRػfm,oN= kguj,O:Y۩q~Q/)jr.wBqe,We?I9yGFu?u& .=ޣ.l7mڛ@ݰ rW_ UNFl`/cvÉ\ M=Lȣ ´c ȻU %-̯e> o cVI/.@::BVַֺ `I msvTen炩sԧ2N/;~F}m0:;|p[+/Q"4te9C;`O@lR0ehE1%։?۴,(ui'4@]sM.?0gV`WTy%wh"Eufޗ=H^NI&?kҿ.LX?*,7}XUy 5cA@iBw#K8]*v&N y\ C_wRa2C9Ls5v'%C?-D3;S=mlGu X#v HCJ䳻R[2{^%,\`cqS?= R#osj #Z  ~ )G\W{ӗ՗=۳ g> gL>Ӄm -):VP_>{ס˝jiUy| Id?ۋ۱ ;Dk 2!|PߍŎ~z9Jךi6F0ݯ '⴩aVd82J{V {j[-'rHϝ/ GX[r@`jn!4R [S3hY-sp|[Y?9 c>8i)i9Hݥ5wCMA(g ֞=s3>:%g~o\o1-&w/B{S}F -4۽&m{j[5@\րY]o uhÔПTw]99+IG~Sqw9;!՛Vї`o;1!/gJ9줬;Zc H(P+WQoO{cԚ~nhsqeևz1qjȱmGDE%q ެ92*K@j P+;hz t(Y> Lΐ A.Q])sAbbmCv??s(P+gE򵛡'QWeVRvGv!s?NvRNV@]Œo>@Z}ȋ<50sj rVXF*/E 7B֥!Z}6mUGqQg/6[Dz࣓T.xg |} @lcJK`AZ([|Lm;HtcN3P7pb_x{`}n>CJ; .h0r0 F&j8!Ŝa:*P]WHW]n`X{ >p}_G2H?ȇ aԟL_\>㋁Or\ÂmG媕* W~ 7">FZ8 :v&yvڰ0@{mwyݗɒIl Nglr0eЦ_Km+B?344y]qYPz'A5`n=Uhq*LlK+ IвpGrQzY:E7PFSx(uC[j_p: :O?TT356rxT'z.HHu^k`ewot:(-dUc" ik֣ DB/~I=bєr#~3ߞ7v^~҆ehG8~;Y/*([ UY| ](@xd(4@Uo^_y S=研Zc19 h/uorU_XDa /3)F-}8-?VKnub F,v-V.Be|گJ|  ɤ*Ϳʫb?&:,T) k4g?&d(^(5LuEFz k2b.^UU&m&yzN;֕_."GenвW3fj,~YОdg8ʃKrB]uΟ;su2G.Ol24@ %̑-ރ4#>:|4X yd%-<䀐? D={B _L17wHh;~P<@_W95) .9aP؀prEYh PN@t;560qEckاiUh< 7h1Fad Qs;-/-g]u0|#rxp\)'5eV`g 1orbкo bK\ r9roXc٫Mki+o.r }?фp׮xp-K7QAG q|Ԕ;5@q@LB&z2!̷fM>壦,=@9/wך)Ȩ+A[ PH PnHC &ͺ7ӆ@EO+} m?*xr)5eȃ/9gaLʑK83'u@^͠Y.{0r~;G* wP:0{t;>p&v3[=Gus+>&yF] i`A k֯b^^fEACrc]?*eN wkfݎüW`'OI '.m'P:y=9#0Toͅ O*oNCB*@Ϫ,# e*3E\yr2Or!yB/i$ػ_{\$'T= sRtBײ2. ݆wVL [U y=4 vM+pڲU+HF$(!rڂ%gDrfT4h^s?ڍk*%j@K-BdJR+4mЕopJf Y#VC|v__Jo/НJ`@+roTO|D% Y{>߯ikAv}P6qfQB;B@5NR+sþدqhIM,tO|u6@b#%)ڗ|dpΊKU}`rM!:@fݜs/ҽbEr l/^q]F ߫@>-^HbT: Z x%o;DEgt|`hH7[/FhrȎPX2\Iȓa uz^1"j 4ބ*_^Ne{AxMe@/⳿Ռ|p#D kPCo@2!ș;'|}e *$;Os^Q$/D\Euݧg C|tGuׅBM Cj,玮9W{%꼐zxm*H|t!ժIOȷyKE֥l`ҀB#UbΦU߂']qn?WiӼላ7C/ٟ;i*H|/wZ.yV4;0c\8[\XAZ|jgt[=lq(q7_BrbۢwSM>Ar;QY F^#uBέU5dg÷?j5Ø#f5I'a_qmzvxnuDX>:nO=?N 7e~JJ,m 凪u^WׄiLtF4eԯбy"!uo2Pz EzZ^=a^RI>53w+ )9C߿mkd (^(#z ~0kbuL EB Wgbw15cadПS^mKW`lg5 zcZY]6\NO#+3uX/Oy g!jlˌL|tT]\QZ7\J*ms!zbsWx4sӡBrzY3aYD@|xrԬ.zZ}f5ݷsU(\P1c\rs 7m\/S=Rȗh~;']ycB Otn!>qQZY'93H)B@nccA+u#W=UGpFJZPT"$x)\7[H|tt(WtH|/'>::C+ :$ !ˉ@BGAB`zE!@rп@!0d@{9~^Q o?P Y(^N|tt(WtH|/'>::C+ :$ !ˉ@cj^591 18w0:n} K/'  SWX_EB`zE!p}(U$&f$>]a`Z9muG[^Q\.LkiE#uN>ޤ,i})Cꏰ^o$>*VGVd {G :#+ kd]hmMOMG#x1I$ Aϱv@!-!@vѢGSfz'GOd60 #M(<ʉܳ6 hS5a!W"xB;U9&GQO]@Gv3DF{/]4f|>MO tm䩿g#.*_gw5r$g-:mca8Xf ksG Q:Oh$6#PXp1 1.o('RdvU;!T"2-xpHk7!6?Dcol@(Y/[ F9_sVIENDB`(D <I >G?G@K @M@IAQBSDUDYFXFPB[H]H[H]I_L[JH@JBKDLDNF\L]OUKPIVL`I`L` Me Qb PhTeShTiW`QaSeUaTfWmYgXjXlYo\o]p^S KS!LV%OW&P\&SY)R[+T\,U^/X_0Xg&[i!Zm"]n$^n)_a2Zf3^c5\d5\o%`q!`u!ar%au&cs,dx*fz.h}.kh5`i=cv4h{0k~2mv;j|s=tBuDxJyK{K}H}L~ZzX|^}\~``\PSVXZ_\]b`eghjm`jrtbfhkmlvz|fmosvy{~}£ĨƬȫijƵ˰ͱ̶ɺαͶʻϺ˼̽οеѺԻսbE3Dbssqqsoqs`aEE339ͯBDWboBߪX84<56<39Y9bDoVqqV:WPPs:V`as:V:<s:Vqsq:Vs:Vs:Vqts:V:̂43;q:VZZs;V_bs:Vs:VPVs: c\ Ys F%c xH#c# 4 xH%ee,,X xH#cwxH%e wN#S  m#  %  !# 7*S}0%v,M %!Jd%JgLv2%J}R%&GI/ %hiM$Jh1$ihf"$.lh h/nf$$z.   $          yI$       ?     $I F$       K      yŔ) @)     " @k||hK )K k j )  )  jU 'UQ j  >  j        >j         \ +         Uk         A K ȟ' T \ T u*  ( =ԅ  Tŭu*                                                                                                                                                                                                                                    CO^aprqooqq]`EE`??( @D <I >G?J @M@PBSDUEYFWGR E]H]JX HIANFWJZM`J`KbLaL` Ma MeRh SbPhVgVcUnZn[jYV$NY)R[*T^/Xh'[m(^a2Ze1\b4\d5\s#at ar&`q*bt(cu-eg;ah;au1gv9jz;moDhrIltKn}@qwNq|Uv3n:s=r?tDu@wEzJ|QT}^}OV_aeg`otejmvxz~nnwzx Ȭ̮̽г־/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq(**+%kq;7VP92  ,  D  JY |m pw YQ@] NY 0bD?n b NY . 1^gSv RR 1!     iE oA  4/    :6 [}   _5  Fvj&         )+((( D <J ?F>M AQBTDXFXG\H]I^ MH@KCLDQFQG]NaLgWhVmZkYo\r_S KZ)Sm#]b4[d6]n0b{2j}0l|4llAfnChqGk{BosJmuMo~Bq|VwUx9r>v@rAvFzJyY|SitlrrvzäǩǷ̾ϼж  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq   3"&L6G2?%#I!<(BP O;HAE <)CQ NM=0:7RD**- M@MS D .87-  ,J/>1/4F9M'$5 (@ F<3E =D D dD D L @_ L\H_Ip]}`J`J`JTWFVESCOAK ?H >E ɫ`I`J`JdO`J`Jq]}`J`J`Jr_`J`J`J`J`J`J`J\HWEd"WD D H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H >H ?H ?5G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >G >F <3E = 3.9 #BreakStringLiterals: false pmdk-1.4.1/src/.gitignore000066400000000000000000000002631331545616200152360ustar00rootroot00000000000000*.so *.so.* *.a *.pc tags TAGS cscope.in.out cscope.out cscope.po.out debug/ nondebug/ *.sdf *.opensdf *.opendb *.log *.suo *.vcxproj.user .vs/ x64/ Generated files/ srcversion.h pmdk-1.4.1/src/LongPath.manifest000066400000000000000000000005231331545616200165110ustar00rootroot00000000000000 true pmdk-1.4.1/src/LongPathSupport.props000066400000000000000000000006321331545616200174440ustar00rootroot00000000000000 $(SolutionDir)LongPath.manifest pmdk-1.4.1/src/Makefile000066400000000000000000000213001331545616200147010ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # src/Makefile -- Makefile for PMDK # TOP := $(dir $(lastword $(MAKEFILE_LIST))).. include $(TOP)/src/common.inc include $(TOP)/src/version.inc TARGETS = libpmem libvmem libpmemblk libpmemlog libpmemobj libpmempool\ libpmemcto libvmmalloc tools ALL_TARGETS = $(TARGETS) common librpmem examples benchmarks SCOPE_DIRS = $(TARGETS) common librpmem rpmem_common DEBUG_RELEASE_TARGETS = common libpmem libvmem libpmemblk libpmemlog libpmemobj\ libpmempool libvmmalloc librpmem libpmemcto RELEASE_TARGETS = tools examples benchmarks CLEAN_NO_JE_TARGETS = $(ALL_TARGETS) rpmem_common test CLEAN_TARGETS = $(CLEAN_NO_JE_TARGETS) jemalloc CLOBBER_NO_JE_TARGETS = $(ALL_TARGETS) rpmem_common test CLOBBER_TARGETS = $(CLOBBER_NO_JE_TARGETS) jemalloc CSTYLE_TARGETS = $(ALL_TARGETS) test rpmem_common INSTALL_TARGETS = $(TARGETS) SPARSE_TARGETS = $(ALL_TARGETS) test rpmem_common HEADERS_DESTDIR = $(DESTDIR)$(includedir) HEADERS_INSTALL = include/libpmem.h include/libvmem.h\ include/libpmemobj.h include/libpmempool.h\ include/libpmemblk.h include/libpmemlog.h\ include/libvmmalloc.h include/libpmemcto.h OBJ_HEADERS_INSTALL = include/libpmemobj/*.h CPP_HEADERS_DESTDIR = $(DESTDIR)$(includedir)/libpmemobj++ PKG_CONFIG_DESTDIR = $(DESTDIR)$(pkgconfigdir) PKG_CONFIG_COMMON = common.pc PKG_CONFIG_FILES = libpmem.pc libvmem.pc libvmmalloc.pc libpmemobj.pc\ libpmemlog.pc libpmemblk.pc libpmempool.pc libpmemobj++.pc\ libpmemcto.pc ifeq ($(BUILD_RPMEM),y) PKG_CONFIG_FILES += librpmem.pc HEADERS_INSTALL += include/librpmem.h INSTALL_TARGETS += librpmem endif rwildcard=$(strip $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)\ $(filter $(subst *,%,$2),$d))) SCOPE_SRC_DIRS = $(SCOPE_DIRS) include jemalloc/src SCOPE_HDR_DIRS = $(SCOPE_DIRS) include jemalloc/src\ jemalloc/include/jemalloc\ jemalloc/include/jemalloc/internal\ debug/libvmem/jemalloc/include/jemalloc\ debug/libvmmalloc/jemalloc/include/jemalloc\ debug/libpmemcto/jemalloc/include/jemalloc\ debug/libvmem/jemalloc/include/jemalloc/internal\ debug/libvmmalloc/jemalloc/include/jemalloc/internal\ debug/libpmemcto/jemalloc/include/jemalloc/internal\ nondebug/libvmem/jemalloc/include/jemalloc\ nondebug/libvmmalloc/jemalloc/include/jemalloc\ nondebug/libpmemcto/jemalloc/include/jemalloc\ nondebug/libvmem/jemalloc/include/jemalloc/internal\ nondebug/libvmmalloc/jemalloc/include/jemalloc/internal\ nondebug/libpmemcto/jemalloc/include/jemalloc/internal SCOPE_SRC_FILES = $(foreach d, $(SCOPE_SRC_DIRS), $(wildcard $(d)/*.c)) SCOPE_HDR_FILES = $(foreach d, $(SCOPE_HDR_DIRS), $(wildcard $(D)/*.h)) SCOPEFILES = $(SCOPE_SRC_FILES) $(SCOPE_HDR_FILES) # include/lib*.h - skip include/pmemcompat.h HEADERS =\ $(foreach f, $(wildcard\ freebsd/include/*.h\ freebsd/include/*/*.h\ include/lib*.h\ include/libpmemobj/*.h\ include/libpmemobj++/*.hpp\ include/libpmemobj++/detail/*.hpp\ windows/include/*.h\ windows/include/*/*.h\ ), $(f)) ifneq ($(filter 1 2, $(CSTYLEON)),) TMP_HEADERS := $(addprefix debug/, $(addsuffix tmp, $(HEADERS))) endif SCRIPTS = $(call rwildcard,,*.sh) debug/%.htmp: %.h $(call check-cstyle, $<, $@) debug/%.hpptmp: %.hpp $(call check-cstyle, $<, $@) all: $(TMP_HEADERS) $(ALL_TARGETS) install: $(INSTALL_TARGETS:=-install) uninstall: $(INSTALL_TARGETS:=-uninstall) clean: $(CLEAN_TARGETS:=-clean) clobber: $(CLOBBER_TARGETS:=-clobber) cstyle: $(CSTYLE_TARGETS:=-cstyle) format: $(CSTYLE_TARGETS:=-format) examples benchmarks: $(TARGETS) benchmarks: examples sparse: $(SPARSE_TARGETS:=-sparse) custom_build = $(DEBUG)$(OBJDIR) libvmmalloc libvmem libpmemcto: jemalloc tools: libpmem libpmemblk libpmemlog libpmemobj libpmemcto libpmemblk libpmemlog libpmemobj libpmemcto: libpmem benchmarks test tools: common pkg-cfg-common: @printf "version=%s\nlibdir=%s\nprefix=%s\n" "$(SRCVERSION)" "$(libdir)" "$(prefix)" > $(PKG_CONFIG_COMMON) $(PKG_CONFIG_COMMON): pkg-cfg-common %.pc: $(PKG_CONFIG_COMMON) $(TOP)/utils/%.pc.in @echo Generating $@ @cat $(PKG_CONFIG_COMMON) > $@ @cat $(TOP)/utils/$@.in >> $@ pkg-config: $(PKG_CONFIG_FILES) $(eval $(call sub-target,$(INSTALL_TARGETS),install,y)) $(eval $(call sub-target,$(INSTALL_TARGETS),uninstall,y)) $(eval $(call sub-target,$(CLEAN_NO_JE_TARGETS),clean,y)) $(eval $(call sub-target,$(CLOBBER_NO_JE_TARGETS),clobber,y)) $(eval $(call sub-target,$(CSTYLE_TARGETS),cstyle,n)) $(eval $(call sub-target,$(CSTYLE_TARGETS),format,n)) $(eval $(call sub-target,$(SPARSE_TARGETS),sparse,n)) $(DEBUG_RELEASE_TARGETS): $(MAKE) -C $@ ifeq ($(custom_build),) $(MAKE) -C $@ DEBUG=1 endif $(RELEASE_TARGETS): $(MAKE) -C $@ jemalloc-check: jemalloc-test test: all jemalloc-test $(MAKE) -C test test check pcheck: test jemalloc-check $(MAKE) -C test $@ check-remote: test $(MAKE) -C test $@ jemalloc jemalloc-clean jemalloc-clobber jemalloc-test jemalloc-check: $(MAKE) -C jemalloc -f Makefile.libvmem $@ EXTRA_CFLAGS="$(EXTRA_CFLAGS) -I$(abspath $(TOP))/src/common" $(MAKE) -C jemalloc -f Makefile.libvmmalloc $@ EXTRA_CFLAGS="$(EXTRA_CFLAGS) -I$(abspath $(TOP))/src/common" $(MAKE) -C jemalloc -f Makefile.libpmemcto $@ EXTRA_CFLAGS="$(EXTRA_CFLAGS) -I$(abspath $(TOP))/src/common" ifeq ($(custom_build),) $(MAKE) -C jemalloc -f Makefile.libvmem $@ DEBUG=1 EXTRA_CFLAGS="$(EXTRA_CFLAGS) -I$(abspath $(TOP))/src/common" $(MAKE) -C jemalloc -f Makefile.libvmmalloc $@ DEBUG=1 EXTRA_CFLAGS="$(EXTRA_CFLAGS) -I$(abspath $(TOP))/src/common" $(MAKE) -C jemalloc -f Makefile.libpmemcto $@ DEBUG=1 EXTRA_CFLAGS="$(EXTRA_CFLAGS) -I$(abspath $(TOP))/src/common" endif install-cpp: $(call install_recursive_filter,include/libpmemobj++,*.hpp,0644,$(CPP_HEADERS_DESTDIR)) install: install-cpp uninstall-cpp: $(foreach f, include/libpmemobj++/*.hpp, $(RM) $(HEADERS_DESTDIR)/libpmemobj++/$(notdir $(f))) $(foreach f, include/libpmemobj++/detail/*.hpp, $(RM) $(HEADERS_DESTDIR)/libpmemobj++/detail/$(notdir $(f))) uninstall: uninstall-cpp # Re-generate pkg-config files on 'make install' (not on 'make all'), # to handle the case when prefix is specified only for 'install'. # Clean up generated files when done. install: all pkg-config install -d $(HEADERS_DESTDIR) install -p -m 0644 $(HEADERS_INSTALL) $(HEADERS_DESTDIR) install -d $(HEADERS_DESTDIR)/libpmemobj install -p -m 0644 $(OBJ_HEADERS_INSTALL) $(HEADERS_DESTDIR)/libpmemobj install -d $(PKG_CONFIG_DESTDIR) install -p -m 0644 $(PKG_CONFIG_FILES) $(PKG_CONFIG_DESTDIR) $(RM) $(PKG_CONFIG_FILES) uninstall: $(foreach f, $(HEADERS_INSTALL), $(RM) $(HEADERS_DESTDIR)/$(notdir $(f))) $(foreach f, $(OBJ_HEADERS_INSTALL), $(RM) $(HEADERS_DESTDIR)/libpmemobj/$(notdir $(f))) $(foreach f, $(PKG_CONFIG_FILES), $(RM) $(PKG_CONFIG_DESTDIR)/$(notdir $(f))) cstyle: $(STYLE_CHECK) check $(HEADERS) $(CHECK_SHEBANG) $(SCRIPTS) format: $(STYLE_CHECK) format $(HEADERS) cscope: cscope -q -b $(SCOPEFILES) ctags -e $(SCOPEFILES) clean-here: $(RM) tags cscope.in.out cscope.out cscope.po.out *.pc $(TMP_HEADERS) clean: clean-here clobber: clean-here .NOTPARALLEL: libvmem libvmmalloc libpmemcto .PHONY: all install uninstall uninstall-cpp install-cpp clean clobber cstyle\ format test check pcheck jemalloc jemalloc-clean jemalloc-test\ jemalloc-check cscope $(ALL_TARGETS) pkg-config check-remote clean-here\ pkg-cfg-common pmdk-1.4.1/src/Makefile.inc000066400000000000000000000211551331545616200154610ustar00rootroot00000000000000# Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # src/Makefile.inc -- common Makefile rules for PMDK # TOP := $(dir $(lastword $(MAKEFILE_LIST))).. include $(TOP)/src/common.inc INCLUDE = $(TOP)/src/include RPMEM_COMMON = $(TOP)/src/rpmem_common vpath %.c $(RPMEM_COMMON) COMMON = $(TOP)/src/common vpath %.c $(COMMON) INCS += -I../include -I../common/ $(OS_INCS) # default CFLAGS DEFAULT_CFLAGS += -std=gnu99 DEFAULT_CFLAGS += -Wall DEFAULT_CFLAGS += -Werror DEFAULT_CFLAGS += -Wmissing-prototypes DEFAULT_CFLAGS += -Wpointer-arith DEFAULT_CFLAGS += -Wsign-conversion DEFAULT_CFLAGS += -Wsign-compare ifeq ($(call check_Wconversion), y) DEFAULT_CFLAGS += -Wconversion endif ifeq ($(call check_compiler, icc), n) DEFAULT_CFLAGS += -Wunused-macros DEFAULT_CFLAGS += -Wmissing-field-initializers ifeq ($(call check_flag, -Wunreachable-code-return), y) DEFAULT_CFLAGS += -Wunreachable-code-return endif ifeq ($(call check_flag, -Wmissing-variable-declarations), y) DEFAULT_CFLAGS += -Wmissing-variable-declarations endif endif ifeq ($(DEBUG),1) # Undefine _FORTIFY_SOURCE in case it's set in system-default or # user-defined CFLAGS as it conflicts with -O0. DEBUG_CFLAGS += -Wp,-U_FORTIFY_SOURCE DEBUG_CFLAGS += -O0 -ggdb -DDEBUG LIB_SUBDIR = /pmdk_debug OBJDIR = debug else DEFAULT_CFLAGS += -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 LIB_SUBDIR = OBJDIR = nondebug endif # use defaults, if system or user-defined CFLAGS are not specified CFLAGS ?= $(DEFAULT_CFLAGS) CFLAGS += -std=gnu99 CFLAGS += -fno-common CFLAGS += -pthread CFLAGS += -DSRCVERSION=\"$(SRCVERSION)\" ifeq ($(COVERAGE),1) CFLAGS += $(GCOV_CFLAGS) LDFLAGS += $(GCOV_LDFLAGS) LIBS += $(GCOV_LIBS) endif ifeq ($(VALGRIND),0) CFLAGS += -DVALGRIND_ENABLED=0 CXXFLAGS += -DVALGRIND_ENABLED=0 endif # On FreeBSD libvmmalloc defines pthread_create, which conflicts with asan tsanitize := $(SANITIZE) ifeq ($(shell uname -s),FreeBSD) ifeq ($(JEMALLOC_PMDKDIR),libvmmalloc) hasaddrcomma := address, tsanitize := $(subst address,,$(subst $(hasaddrcomma),,$(SANITIZE))) ifneq ($(tsanitize),$(SANITIZE)) $(info SANITIZE=address not supported for libvmmalloc, ignored) endif endif endif ifneq ($(tsanitize),) CFLAGS += -fsanitize=$(tsanitize) LDFLAGS += -fsanitize=$(tsanitize) endif CFLAGS += $(EXTRA_CFLAGS) ifeq ($(DEBUG),1) CFLAGS += $(EXTRA_CFLAGS_DEBUG) $(DEBUG_CFLAGS) else CFLAGS += $(EXTRA_CFLAGS_RELEASE) endif LDFLAGS += -Wl,-z,relro -Wl,--fatal-warnings -Wl,--warn-common $(EXTRA_LDFLAGS) ifneq ($(NORPATH),1) LDFLAGS += -Wl,-rpath=$(libdir)$(LIB_SUBDIR) endif # XXX: required by clock_gettime(), if glibc version < 2.17 # The os_clock_gettime() function is now in OS abstraction layer, # linked to all the librariess, unit tests and benchmarks. ifeq ($(call check_librt), n) LIBS += -lrt endif define arch32_error_msg ################################################## ### 32-bit builds of PMDK are not supported! ### ### Please, use 64-bit platform/compiler. ### ################################################## endef TESTCMD := $(CC) $(CFLAGS) -dM -E -x c /dev/null -o /dev/null TESTBUILD := $(shell $(TESTCMD) && echo 1 || echo 0) ifneq ($(TESTBUILD), 1) $(error "$(TESTCMD)" failed) endif ARCH := $(call get_arch) ifneq ($(ARCH), x86_64) ifneq ($(ARCH), aarch64) $(error unsupported architecture: $(ARCH)) endif endif LP64 := $(shell $(CC) $(CFLAGS) -dM -E -x c /dev/null | grep -Ec "__SIZEOF_LONG__.+8|__SIZEOF_POINTER__.+8" ) ifneq ($(LP64), 2) $(error $(arch32_error_msg)) endif LIBS_DESTDIR = $(DESTDIR)$(libdir)$(LIB_SUBDIR) DIRNAME = $(shell basename $(CURDIR)) ifeq ($(OBJDIR),$(abspath $(OBJDIR))) objdir = $(OBJDIR)/$(DIRNAME) else objdir = ../$(OBJDIR)/$(DIRNAME) endif LIB_OUTDIR ?= $(objdir)/.. ifneq ($(LIB_OUTDIR),) LDFLAGS += -L$(LIB_OUTDIR) endif ifneq ($(SOURCE),) _OBJS = $(SOURCE:.c=.o) _OBJS_COMMON = $(patsubst $(COMMON)/%, %, $(_OBJS)) _OBJS_RPMEM_COMMON = $(patsubst $(RPMEM_COMMON)/%, %, $(_OBJS_COMMON)) OBJS += $(addprefix $(objdir)/, $(_OBJS_RPMEM_COMMON)) endif ifneq ($(HEADERS),) ifneq ($(filter 1 2, $(CSTYLEON)),) TMP_HEADERS := $(addsuffix tmp, $(HEADERS)) TMP_HEADERS := $(addprefix $(objdir)/, $(TMP_HEADERS)) endif endif ifneq ($(LIBRARY_NAME),) LIB_NAME = lib$(LIBRARY_NAME) endif ifneq ($(LIBRARY_SO_VERSION),) LIB_MAP = $(LIB_NAME).map LIB_SONAME = $(LIB_NAME).so.$(LIBRARY_SO_VERSION) LIB_SO = $(LIB_OUTDIR)/$(LIB_NAME).so LIB_SO_SONAME = $(LIB_SO).$(LIBRARY_SO_VERSION) ifneq ($(LIBRARY_VERSION),) LIB_SO_REAL = $(LIB_SO_SONAME).$(LIBRARY_VERSION) else $(error LIBRARY_VERSION not set) endif TARGET_LIBS = $(LIB_SO_REAL) TARGET_LINKS = $(LIB_SO_SONAME) $(LIB_SO) endif ifneq ($(LIB_NAME),) LIB_AR = $(LIB_OUTDIR)/$(LIB_NAME).a LIB_AR_UNSCOPED = $(objdir)/$(LIB_NAME)_unscoped.o LIB_AR_ALL = $(objdir)/$(LIB_NAME)_all.o TARGET_LIBS += $(LIB_AR) endif ifneq ($(EXTRA_TARGETS),) EXTRA_TARGETS_CLEAN = $(EXTRA_TARGETS:=-clean) EXTRA_TARGETS_CLOBBER = $(EXTRA_TARGETS:=-clobber) endif PMEMLOG_PRIV_OBJ=$(LIB_OUTDIR)/libpmemlog/libpmemlog_unscoped.o PMEMBLK_PRIV_OBJ=$(LIB_OUTDIR)/libpmemblk/libpmemblk_unscoped.o ifneq ($(LIBPMEMLOG_PRIV_FUNCS),) OBJS += pmemlog_priv_funcs.o endif ifneq ($(LIBPMEMBLK_PRIV_FUNCS),) OBJS += pmemblk_priv_funcs.o endif MAKEFILE_DEPS=../Makefile.inc Makefile $(TOP)/src/common.inc all: $(objdir) $(LIB_OUTDIR) $(EXTRA_TARGETS) $(LIB_AR) $(LIB_SO_SONAME) $(LIB_SO_REAL) $(LIB_SO) $(TMP_HEADERS) $(objdir) $(LIB_OUTDIR): $(MKDIR) -p $@ $(LIB_SO_REAL): $(OBJS) $(EXTRA_OBJS) $(LIB_MAP) $(MAKEFILE_DEPS) $(CC) $(LDFLAGS) -shared -Wl,--version-script=$(LIB_MAP),-soname,$(LIB_SONAME) -o $@ $(OBJS) $(EXTRA_OBJS) $(LIBS) $(LIB_SO_SONAME): $(LIB_SO_REAL) $(MAKEFILE_DEPS) $(LN) -sf $(shell basename $<) $@ $(LIB_SO): $(LIB_SO_SONAME) $(MAKEFILE_DEPS) $(LN) -sf $(shell basename $<) $@ $(LIB_AR_UNSCOPED): $(OBJS) $(EXTRA_OBJS) $(MAKEFILE_DEPS) $(LD) -o $@ -r $(OBJS) $(EXTRA_OBJS) ifeq ($(LIB_MAP),) $(LIB_AR_ALL): $(LIB_AR_UNSCOPED) $(MAKEFILE_DEPS) $(OBJCOPY) $< $@ else $(LIB_AR_ALL): $(LIB_AR_UNSCOPED) $(LIB_MAP) $(MAKEFILE_DEPS) $(OBJCOPY) --localize-hidden `sed -n 's/^ *\([a-zA-Z0-9_]*\);$$/-G \1/p' $(LIB_MAP)` $< $@ endif $(LIB_AR): $(LIB_AR_ALL) $(MAKEFILE_DEPS) $(AR) rv $@ $(LIB_AR_ALL) $(PMEMBLK_PRIV_OBJ): $(MAKE) -C $(LIBSDIR) libpmemblk install: all ifneq ($(LIBRARY_NAME),) $(INSTALL) -d $(LIBS_DESTDIR) $(INSTALL) -p -m 0755 $(TARGET_LIBS) $(LIBS_DESTDIR) $(CP) -d $(TARGET_LINKS) $(LIBS_DESTDIR) endif uninstall: ifneq ($(LIBRARY_NAME),) $(foreach f, $(TARGET_LIBS), $(RM) $(LIBS_DESTDIR)/$(notdir $(f))) $(foreach f, $(TARGET_LINKS), $(RM) $(LIBS_DESTDIR)/$(notdir $(f))) endif clean: $(EXTRA_TARGETS_CLEAN) ifneq ($(LIBRARY_NAME),) $(RM) $(OBJS) $(TMP_HEADERS) $(RM) $(LIB_AR_ALL) $(LIB_AR_UNSCOPED) endif clobber: clean $(EXTRA_TARGETS_CLOBBER) ifneq ($(LIBRARY_NAME),) $(RM) $(LIB_AR) $(LIB_SO_SONAME) $(LIB_SO_REAL) $(LIB_SO) $(RM) -r $(objdir)/.deps endif $(eval $(cstyle-rule)) $(objdir)/%.o: %.c $(MAKEFILE_DEPS) $(call check-cstyle, $<) @mkdir -p $(objdir)/.deps $(CC) -MD -c -o $@ $(CFLAGS) $(INCS) -fPIC $(call coverage-path, $<) $(call check-os, $@, $<) $(create-deps) sparse: $(if $(SOURCE), $(sparse-c)) $(objdir)/%.htmp: %.h $(call check-cstyle, $<, $@) .PHONY: all clean clobber install uninstall cstyle -include $(objdir)/.deps/*.P pmdk-1.4.1/src/PMDK.sln000066400000000000000000004776011331545616200145350ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog_minimal", "examples\libpmemobj\pmemlog\obj_pmemlog_minimal.vcxproj", "{0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_movnt_align", "test\pmem_movnt_align\pmem_movnt_align.vcxproj", "{025E7D51-41F2-4CBA-956E-C37A4443DB1B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "full_copy", "examples\libpmem\full_copy.vcxproj", "{0287C3DC-AE03-4714-AAFF-C52F062ECA6F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "traces_custom_function", "test\traces_custom_function\traces_custom_function.vcxproj", "{02BC3B44-C7F1-4793-86C1-6F36CA8A7F53}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_memblock", "test\obj_memblock\obj_memblock.vcxproj", "{0388E945-A655-41A7-AF27-8981CEE0E49A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_check_version", "test\vmem_check_version\vmem_check_version.vcxproj", "{04345B7D-B0A1-405B-8BB2-5B98A3400FEF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_callbacks", "test\obj_tx_callbacks\obj_tx_callbacks.vcxproj", "{0529575C-F6E8-44FD-BB82-82A29948D0F2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "out_err_mt", "test\out_err_mt\out_err_mt.vcxproj", "{063037B2-CA35-4520-811C-19D9C4ED891E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog_macros", "examples\libpmemobj\pmemlog\obj_pmemlog_macros.vcxproj", "{06877FED-15BA-421F-85C9-1A964FB97446}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_ptr_arith", "test\obj_cpp_ptr_arith\obj_cpp_ptr_arith.vcxproj", "{06FCFDE9-8C88-4B7D-B87A-47953DB203C9}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_mt", "test\obj_tx_mt\obj_tx_mt.vcxproj", "{0703E813-9CC8-4DEA-AA33-42B099CD172D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_heap_interrupt", "test\obj_heap_interrupt\obj_heap_interrupt.vcxproj", "{07A153D9-DF17-4DE8-A3C2-EBF171B961AE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvmem", "libvmem\libvmem.vcxproj", "{08762559-E9DF-475B-BA99-49F4B5A1D80B}" ProjectSection(ProjectDependencies) = postProject {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_parse_size", "test\util_parse_size\util_parse_size.vcxproj", "{08B62E36-63D2-4FF1-A605-4BBABAEE73FB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_include", "test\log_include\log_include.vcxproj", "{0A049EAD-652F-4E20-8026-90FD99AEE77A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmemlog", "libpmemlog\libpmemlog.vcxproj", "{0B1818EB-BDC8-4865-964F-DB8BF05CFD86}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reader", "examples\libpmemobj\string_store\reader.vcxproj", "{0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{0CC6D525-806E-433F-AB4A-6CFD546418B1}" ProjectSection(SolutionItems) = preProject examples\ex_common.h = examples\ex_common.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cuckoo", "test\obj_cuckoo\obj_cuckoo.vcxproj", "{0CDCEB97-3270-4939-A290-EA2D3BE34B0C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_make_persistent_array_atomic", "test\obj_cpp_make_persistent_array_atomic\obj_cpp_make_persistent_array_atomic.vcxproj", "{0DC1B184-C814-448F-8B5F-CFFA6F05156C}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "btree", "examples\libpmemobj\btree.vcxproj", "{0FB8F0FD-276C-413B-97A8-67ABE0C9043B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_direct", "test\obj_direct\obj_direct.vcxproj", "{10469175-EEF7-44A0-9961-AC4E45EFD800}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pi", "examples\libpmemobj\pi.vcxproj", "{11D76FBC-DFAA-4B31-9DB0-206E171E3F94}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmemspoil", "test\tools\pmemspoil\pmemspoil.vcxproj", "{11E158AE-C85A-4A6E-B66A-ED2994709276}" ProjectSection(ProjectDependencies) = postProject {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_map_file", "test\pmem_map_file\pmem_map_file.vcxproj", "{12A1A3EF-202C-4DD0-9B5A-F5126CAB078F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmem", "libpmem", "{1434B17C-6165-4D42-BEA1-5A7730D5A6BB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_recreate", "test\obj_recreate\obj_recreate.vcxproj", "{1464398A-100F-4518-BDB9-939A6362B6CF}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemcto", "libpmemcto", "{16721958-ECE3-4674-9913-9AF8E32F0CD8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dllview", "test\tools\dllview\dllview.vcxproj", "{179BEB5A-2C90-44F5-A734-FA756A5E668C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rbtree_map", "examples\libpmemobj\tree_map\rbtree_map.vcxproj", "{17A4B817-68B1-4719-A9EF-BD8FAB747DE6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_non_zero", "test\blk_non_zero\blk_non_zero.vcxproj", "{18E90E1A-F2E0-40DF-9900-A14E560C9EB4}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {F7C6C6B6-4142-4C82-8699-4A9D8183181B} = {F7C6C6B6-4142-4C82-8699-4A9D8183181B} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemlog", "libpmemlog", "{1A36B57B-2E88-4D81-89C0-F575C9895E36}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmpmap", "test\tools\cmpmap\cmpmap.vcxproj", "{1B871BA2-3F70-4BC9-9DF4-725EB07F6628}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_libpmemblk", "test\ex_libpmemblk\ex_libpmemblk.vcxproj", "{1B9B0D6D-E530-44A6-ADAE-09EA2BDC47DE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmemcto", "libpmemcto\libpmemcto.vcxproj", "{1BA340EC-B0B2-438D-A47C-27F86F604133}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmemobj", "libpmemobj\libpmemobj.vcxproj", "{1BAA1617-93AE-4196-8A1A-BD492FB18AEF}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_mutex", "test\obj_cpp_mutex\obj_cpp_mutex.vcxproj", "{1E564DB1-0687-4CC4-BAE5-453F93052FDA}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "writer", "examples\libpmemobj\string_store_tx_type\writer.vcxproj", "{1EB3DE5B-6357-498D-8CAC-EEC0209EA454}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_lists", "test\win_lists\win_lists.vcxproj", "{1F2E1C51-2B14-4047-BE6D-52E00FC3C780}" ProjectSection(ProjectDependencies) = postProject {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_basic", "test\cto_basic\cto_basic.vcxproj", "{21991E84-7859-420E-ADDA-1D058E787F06}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_dirty", "test\cto_dirty\cto_dirty.vcxproj", "{22DCCD3E-79FF-4F66-A9AA-D033A7671B94}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_recovery", "test\obj_recovery\obj_recovery.vcxproj", "{2498FCDA-E2CC-43EF-9A35-8CD63F253171}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_aligned_alloc", "test\vmem_aligned_alloc\vmem_aligned_alloc.vcxproj", "{25B5C601-03D7-4861-9C0F-7F0453B04227}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_realloc_inplace", "test\cto_realloc_inplace\cto_realloc_inplace.vcxproj", "{26135DD1-8BB0-4217-A4DC-C1F232F35BA2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_transform", "test\pmempool_transform\pmempool_transform.vcxproj", "{26166DF1-3C94-44AF-9075-BA31DCD2F6BB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_out_of_memory", "test\vmem_out_of_memory\vmem_out_of_memory.vcxproj", "{26D24B3D-22CE-44EB-AA21-2BF594F80520}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_test_win", "test\libpmempool_api_win\libpmempool_test_win.vcxproj", "{27FA11C6-431D-41D1-A417-FAB7C4F93DCA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_toid", "test\obj_toid\obj_toid.vcxproj", "{296F3C5D-3951-423E-8E2F-FD4A37958C72}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_include", "test\blk_include\blk_include.vcxproj", "{29D9376B-DC36-4940-83F1-A7CBE38A2103}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_dump", "test\pmempool_dump\pmempool_dump.vcxproj", "{2A1D6AF2-7336-4966-A4B3-0BE9A24BAE00}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "out_err_mt_win", "test\out_err_mt_win\out_err_mt_win.vcxproj", "{2B1A5104-A324-4D02-B5C7-D021FB8F880C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_include", "test\pmem_include\pmem_include.vcxproj", "{2B7772E6-9DAA-4F38-B0BC-7B2399366325}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lists", "examples\libpmemobj\lists.vcxproj", "{2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_locks", "test\obj_locks\obj_locks.vcxproj", "{2DE6B085-3C19-49B1-894A-AD9376000E09}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_create", "test\vmem_create\vmem_create.vcxproj", "{2E7E8487-0BB0-4E8A-8672-ED8ABD80D468}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_action", "test\obj_action\obj_action.vcxproj", "{2ED26FDA-3C4E-4514-B387-5E77C302FF71}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmemdetect", "test\tools\pmemdetect\pmemdetect.vcxproj", "{2EFFC590-BF5E-46A2-AF04-E67E1D571D2E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmempool", "libpmempool", "{2F543422-4B8A-4898-BE6B-590F52B4E9D1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bttcreate", "test\tools\bttcreate\bttcreate.vcxproj", "{3142CB13-CADA-48D3-9A25-E6ACB243760A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_map", "examples\libpmemobj\list_map\list_map.vcxproj", "{3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "traces_pmem", "test\traces_pmem\traces_pmem.vcxproj", "{3B23831B-E5DE-4A62-9D0B-27D0D9F293F4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_check_allocations", "test\vmem_check_allocations\vmem_check_allocations.vcxproj", "{3BAB8FDF-42F7-4D46-AA10-E282FD41B9F2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_pool", "test\log_pool\log_pool.vcxproj", "{3CF270CD-0F56-48E3-AD84-82F369C568BF}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {0B1818EB-BDC8-4865-964F-DB8BF05CFD86} = {0B1818EB-BDC8-4865-964F-DB8BF05CFD86} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemcto", "libpmemcto", "{3D5A802D-CFAF-4C33-A042-D79851F60356}" ProjectSection(SolutionItems) = preProject examples\libpmemcto\README = examples\libpmemcto\README EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_pages_purging", "test\vmem_pages_purging\vmem_pages_purging.vcxproj", "{3D9A580B-5F0F-434F-B4D6-228B8E7ADAA5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "examples\libpmemcto\manpage.vcxproj", "{3DEB4FBF-638D-4588-A510-E9A77FF75BB1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sparsefile", "test\tools\sparsefile\sparsefile.vcxproj", "{3EC30D6A-BDA4-4971-879A-8814204EAE31}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool", "test\obj_pool\obj_pool.vcxproj", "{3ECCB0F1-3ADF-486A-91C5-79DF0FC22F78}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtree_map", "examples\libpmemobj\tree_map\rtree_map.vcxproj", "{3ED56E55-84A6-422C-A8D4-A8439FB8F245}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_malloc", "test\vmem_malloc\vmem_malloc.vcxproj", "{40DC66AD-F66D-4194-B9A4-A3A2222516FE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_info", "test\pmempool_info\pmempool_info.vcxproj", "{42CCEF95-5ADD-460C-967E-DD5B2C744943}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemobj++", "libpmemobj++", "{42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_getopt", "test\win_getopt\win_getopt.vcxproj", "{433F7840-C597-4950-84C9-E4FF7DF6A298}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sys", "sys", "{45027FC5-4A32-47BD-AC5B-66CC7616B1D2}" ProjectSection(SolutionItems) = preProject windows\include\sys\file.h = windows\include\sys\file.h windows\include\sys\mman.h = windows\include\sys\mman.h windows\include\sys\mount.h = windows\include\sys\mount.h windows\include\sys\param.h = windows\include\sys\param.h windows\include\sys\statvfs.h = windows\include\sys\statvfs.h windows\include\sys\uio.h = windows\include\sys\uio.h windows\include\sys\wait.h = windows\include\sys\wait.h EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libvmem", "libvmem", "{45E74E38-35CA-4CB6-8965-BC20D39659AF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool_lookup", "test\obj_pool_lookup\obj_pool_lookup.vcxproj", "{4850F425-9128-4E91-973C-5AE7BD97395B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_libpmemobj_cpp", "test\ex_libpmemobj_cpp\ex_libpmemobj_cpp.vcxproj", "{48A3AE10-200B-454E-9D82-EC1A88CF1151}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmemcommon", "common\libpmemcommon.vcxproj", "{492BAA3D-0D5D-478E-9765-500463AE69AA}" ProjectSection(ProjectDependencies) = postProject {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmap", "examples\libpmemobj\map\libmap.vcxproj", "{49A7CC5A-D5E7-4A07-917F-C6918B982BE8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pvector", "test\obj_pvector\obj_pvector.vcxproj", "{4A3CDA9F-55C2-455E-8E82-1FAAAA2245C5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "util", "util", "{4C291EEB-3874-4724-9CC2-1335D13FF0EE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_alloc", "test\obj_tx_alloc\obj_tx_alloc.vcxproj", "{4C429783-0B01-449F-A36F-C2019233890B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmemalloc", "test\tools\pmemalloc\pmemalloc.vcxproj", "{4C6E7F0A-7E6A-4713-B1D2-B7B4ADC992AF}" ProjectSection(ProjectDependencies) = postProject {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_include", "test\libpmempool_include\libpmempool_include.vcxproj", "{4E334022-7A71-4197-9E15-878F7EFC877E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_custom_alloc", "test\vmem_custom_alloc\vmem_custom_alloc.vcxproj", "{4ED1E400-CF16-48C2-B176-2BF186E73531}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_walker", "test\log_walker\log_walker.vcxproj", "{4FB4FF90-4E92-4CFB-A01F-C73D6861CA03}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_poolset_parse", "test\util_poolset_parse\util_poolset_parse.vcxproj", "{50FD1E47-2131-48D2-9435-5CB28DF6B15A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_checkout", "examples\libpmemblk\assetdb\asset_checkout.vcxproj", "{513C4CFA-BD5B-4470-BA93-F6D43778A754}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemobj_cpp", "libpmemobj_cpp", "{52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Setup", "Setup", "{52B4C136-F527-4FE0-9781-5B2259A0FF27}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_mix_allocations", "test\vmem_mix_allocations\vmem_mix_allocations.vcxproj", "{537F759B-B617-48D9-A2F3-7FB769A8F9B7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_delete", "test\vmem_delete\vmem_delete.vcxproj", "{54E6F8F5-418E-44BE-8DF2-5A60D9EE971B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_mmap", "test\win_mmap\win_mmap.vcxproj", "{5580D11C-FDA6-4CF2-A0E8-1C2D3FBC11F1}" ProjectSection(ProjectDependencies) = postProject {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_checkin", "examples\libpmemblk\assetdb\asset_checkin.vcxproj", "{581B3A58-F3F0-4765-91E5-D0C82816A528}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_basic_integration", "test\obj_basic_integration\obj_basic_integration.vcxproj", "{58386481-30B7-40FC-96AF-0723A4A7B228}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pmempool", "pmempool", "{59AB6976-D16B-48D0-8D16-94360D3FE51D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reader", "examples\libpmemobj\string_store_tx\reader.vcxproj", "{59D7A9CD-9912-40E4-96E1-8A873F777F62}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_memmove", "test\pmem_memmove\pmem_memmove.vcxproj", "{5A391A14-8E29-4788-93FC-EDADED31D32F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_map_file_win", "test\pmem_map_file_win\pmem_map_file_win.vcxproj", "{5AD07646-5E16-4CEF-B80A-BE5EE4D54FEF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_store", "examples\libpmemobj\map\data_store.vcxproj", "{5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_many_size_allocs", "test\obj_many_size_allocs\obj_many_size_allocs.vcxproj", "{5D362DB7-D2BD-4907-AAD8-4B8627E72282}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog_simple", "examples\libpmemobj\pmemlog\obj_pmemlog_simple.vcxproj", "{5DB2E259-0D19-4A89-B8EC-B2912F39924D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_rm", "test\libpmempool_rm\libpmempool_rm.vcxproj", "{5F2B687A-1B42-439C-AEEC-135DD22FB851}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_is_pmem_windows", "test\pmem_is_pmem_windows\pmem_is_pmem_windows.vcxproj", "{5F8A56F8-2C5B-48B6-9654-DD642D3E5F5C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog", "examples\libpmemobj\pmemlog\obj_pmemlog.vcxproj", "{60206D22-E132-4695-8486-10BECA32C5CC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_allocator", "test\obj_cpp_allocator\obj_cpp_allocator.vcxproj", "{6068773F-FDA7-484F-8650-EE1AA5C3CB37}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_backup", "test\libpmempool_backup\libpmempool_backup.vcxproj", "{60B463D4-8CD5-4BF6-A25B-01BE13B87590}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_rw_mt", "test\blk_rw_mt\blk_rw_mt.vcxproj", "{628FADA9-7047-4DD9-BD17-9FE4B5A1ADB0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool_lock", "test\obj_pool_lock\obj_pool_lock.vcxproj", "{63B8184D-85E0-4E6A-9729-558C567D1D1D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemobj", "libpmemobj", "{63C9B3F8-437D-4AD9-B32D-D04AE38C35B6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_strdup", "test\obj_tx_strdup\obj_tx_strdup.vcxproj", "{643B82A1-D009-46A9-92A0-2883399B05C2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_sync", "test\obj_sync\obj_sync.vcxproj", "{6516D6CF-8000-4341-9487-312BC83EE370}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmalloc_basic", "test\obj_pmalloc_basic\obj_pmalloc_basic.vcxproj", "{65D92D98-97E1-48F7-AEF6-75221CF48EA4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_memcpy", "test\pmem_memcpy\pmem_memcpy.vcxproj", "{673277EC-D26B-414D-92E3-84EE873316A8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_rm_win", "test\libpmempool_rm_win\libpmempool_rm_win.vcxproj", "{67AC1343-98FD-4143-92C0-559C55F749F5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_rw", "test\blk_rw\blk_rw.vcxproj", "{6851356E-A5D9-46A6-8262-A7E208729F18}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {F7C6C6B6-4142-4C82-8699-4A9D8183181B} = {F7C6C6B6-4142-4C82-8699-4A9D8183181B} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_common", "test\win_common\win_common.vcxproj", "{6AE1B8BE-D46A-4E99-87A2-F160FB950DCA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_poolset_size", "test\util_poolset_size\util_poolset_size.vcxproj", "{6B492754-9F80-44B3-A2A7-1D98AF06F3B2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_list_macro", "test\obj_list_macro\obj_list_macro.vcxproj", "{6BCEF2A5-0CEC-4CC6-9CB0-D3FBF871A408}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "string_store_tx", "string_store_tx", "{6D63CDF1-F62C-4614-AD8A-95B0A63AA070}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "set_funcs", "test\set_funcs\set_funcs.vcxproj", "{6D7C1169-3246-465F-B630-ECFEF4F3179A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_poolset", "test\util_poolset\util_poolset.vcxproj", "{6F06A19B-0921-4B71-A3A5-B350B5FFEADB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_locks_abort", "test\obj_tx_locks_abort\obj_tx_locks_abort.vcxproj", "{6F4953DA-FDC3-46CF-BF24-3752CCF2E1CB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_out_of_memory", "test\obj_out_of_memory\obj_out_of_memory.vcxproj", "{70EE1D40-0C65-4985-8EFC-BD40EE3A89B2}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_file_open", "test\util_file_open\util_file_open.vcxproj", "{715EADD7-0FFE-4F1F-94E7-49302968DF79}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_calloc", "test\vmem_calloc\vmem_calloc.vcxproj", "{718CA6FA-6446-4E43-83DF-BA4E85E5886B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_check", "test\obj_check\obj_check.vcxproj", "{71D182E0-345A-4375-B0FA-3536821B0EE3}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_make_persistent_array", "test\obj_cpp_make_persistent_array\obj_cpp_make_persistent_array.vcxproj", "{72598DD9-3F44-4E6A-B0B7-C5AE3FF43B1F}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "array", "examples\libpmemobj\array\array.vcxproj", "{7264C8F6-73FB-4830-9306-1558D3EAC71B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_list", "test\obj_list\obj_list.vcxproj", "{729E3905-FF7D-49C5-9871-6D35D839183E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "writer", "examples\libpmemobj\string_store_tx\writer.vcxproj", "{7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lifesaver", "examples\libpmemcto\lifesaver\lifesaver.vcxproj", "{73F35C28-811C-4D77-916E-386EB139C001}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_create_in_region", "test\vmem_create_in_region\vmem_create_in_region.vcxproj", "{74243B75-816C-4077-8DF0-98D2C78B0E5D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{746BA101-5C93-42A5-AC7A-64DCEB186572}" ProjectSection(SolutionItems) = preProject test\match = test\match test\RUNTESTLIB.PS1 = test\RUNTESTLIB.PS1 test\RUNTESTS.ps1 = test\RUNTESTS.ps1 test\unittest\unittest.ps1 = test\unittest\unittest.ps1 EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reader", "examples\libpmemobj\string_store_tx_type\reader.vcxproj", "{74D655D5-F661-4887-A1EB-5A6222AF5FCA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "linux", "linux", "{774627B7-6532-4464-AEE4-02F72CA44F95}" ProjectSection(SolutionItems) = preProject windows\include\linux\limits.h = windows\include\linux\limits.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_pool_lock", "test\blk_pool_lock\blk_pool_lock.vcxproj", "{779425B1-2211-499B-A7CC-4F9EC6CB0D25}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {F7C6C6B6-4142-4C82-8699-4A9D8183181B} = {F7C6C6B6-4142-4C82-8699-4A9D8183181B} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "btree_map", "examples\libpmemobj\tree_map\btree_map.vcxproj", "{79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_ringbuf", "test\obj_ringbuf\obj_ringbuf.vcxproj", "{7D71EE07-6CE2-49FA-8AB8-976800A050A0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool", "tools\pmempool\pmempool.vcxproj", "{7DC3B3DD-73ED-4602-9AF3-8D7053620DEA}" ProjectSection(ProjectDependencies) = postProject {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_libpmem", "test\ex_libpmem\ex_libpmem.vcxproj", "{7DFEB4A5-8B04-4302-9D09-8144918FCF81}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_realloc", "test\vmem_realloc\vmem_realloc.vcxproj", "{7E0106F8-A597-48D5-B4F2-E0FC4D95EE95}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_free", "test\obj_tx_free\obj_tx_free.vcxproj", "{7F51CD29-3BCD-4DD8-B327-F384B5A616D1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_list", "examples\libpmemblk\assetdb\asset_list.vcxproj", "{8008010F-8718-4C5F-86B2-195AEBF73422}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "examples\libpmemblk\manpage.vcxproj", "{8010BBB0-C71B-4EFF-95EB-65C01E5EC197}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_pool_win", "test\blk_pool_win\blk_pool_win.vcxproj", "{80AF1B7D-B8CE-4AF0-AE3B-1DABED1B57E7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_pool_win", "test\cto_pool_win\cto_pool_win.vcxproj", "{8145F442-0EF6-4E55-BAED-8DDE72022355}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{853D45D8-980C-4991-B62A-DAC6FD245402}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_heap", "test\obj_heap\obj_heap.vcxproj", "{85D4076B-896B-4EBB-8F3A-8B44C24CD452}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_debug", "test\obj_debug\obj_debug.vcxproj", "{85DBDA9B-AEF6-43E7-B8B5-05FF2BEC61A3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_heap_state", "test\obj_heap_state\obj_heap_state.vcxproj", "{86EE22CC-6D3C-4F81-ADC8-394946F0DA81}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{877E7D1D-8150-4FE5-A139-B6FBCEAEC393}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmalloc_oom_mt", "test\obj_pmalloc_oom_mt\obj_pmalloc_oom_mt.vcxproj", "{88D239E4-EB7D-4E0A-BE3A-AD78B9F408FC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_strdup", "test\vmem_strdup\vmem_strdup.vcxproj", "{89B6AF14-08A0-437A-B31D-A8A3492FA965}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_add_range_direct", "test\obj_tx_add_range_direct\obj_tx_add_range_direct.vcxproj", "{89F947CA-DDEF-4131-8AFB-584ABA4A1302}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "out_err", "test\out_err\out_err.vcxproj", "{8A0FA780-068A-4534-AA2F-4FF4CF977AF2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_bucket", "test\obj_bucket\obj_bucket.vcxproj", "{8A4872D7-A234-4B9B-8215-82C6BB15F3A2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemblk", "examples\libpmemobj\pmemblk\obj_pmemblk.vcxproj", "{8C42CA7C-1543-4F1B-A55F-28CD419C7D35}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_oid", "test\obj_oid\obj_oid.vcxproj", "{8C6D73E0-0A6F-4487-A040-0EC78D7D6D9A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_shared_mutex", "test\obj_cpp_shared_mutex\obj_cpp_shared_mutex.vcxproj", "{8CD79300-941F-4FDD-A371-92BF0EFBA0FC}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jemalloc", "jemalloc\msvc\jemalloc.vcxproj", "{8D6BB292-9E1C-413D-9F98-4864BDC1514A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_persist_count", "test\obj_persist_count\obj_persist_count.vcxproj", "{8D75FA1A-EC74-4F88-8AC1-CE3F98E4D828}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_snippets", "examples\libpmemobj++\doc_snippets\doc_snippets.vcxproj", "{8DB4158E-96EE-4DE5-A425-C9638F50B9ED}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_flow", "test\obj_tx_flow\obj_tx_flow.vcxproj", "{8E374371-30E1-4623-8755-2A2F3742170B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_make_persistent", "test\obj_cpp_make_persistent\obj_cpp_make_persistent.vcxproj", "{8F42055F-FFD9-4B10-B266-6DD32923F0AC}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srcversion", "windows\srcversion\srcversion.vcxproj", "{901F04DB-E1A5-4A41-8B81-9D31C19ACD59}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_pool", "test\obj_cpp_pool\obj_cpp_pool.vcxproj", "{90C5FCF1-8243-4988-A4EA-AA6A88268373}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_stats", "test\cto_stats\cto_stats.vcxproj", "{91365DAC-BF62-4B96-919D-7C474D029B61}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "windows\getopt\getopt.vcxproj", "{9186EAC4-2F34-4F17-B940-6585D7869BCD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemlog", "libpmemlog", "{91C30620-70CA-46C7-AC71-71F3C602690E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_realloc", "test\obj_realloc\obj_realloc.vcxproj", "{91E19AEB-7B75-43E0-B8B4-D2BB60D839EA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_create", "test\pmempool_create\pmempool_create.vcxproj", "{92388A20-50FC-45F8-89E3-71F1618EFABB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compat_incompat_features", "test\compat_incompat_features\compat_incompat_features.vcxproj", "{924B2937-0B53-4DC6-B7E1-5F3102728F89}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_check_allocations", "test\cto_check_allocations\cto_check_allocations.vcxproj", "{940C5974-9EF3-4FAC-9820-976B0711F69B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_pool", "test\blk_pool\blk_pool.vcxproj", "{95B683BD-B9DC-400F-9BC0-8F1505F08BF5}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {F7C6C6B6-4142-4C82-8699-4A9D8183181B} = {F7C6C6B6-4142-4C82-8699-4A9D8183181B} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{95FAF291-03D1-42FC-9C10-424D551D475D}" ProjectSection(SolutionItems) = preProject common\common.rc = common\common.rc EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_movnt", "test\pmem_movnt\pmem_movnt.vcxproj", "{96D00A19-5CEF-4CC5-BDE8-E33C68BCE90F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_cpuid", "test\util_cpuid\util_cpuid.vcxproj", "{98ACBE5D-1A92-46F9-AA81-533412172952}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_redo_log", "test\obj_redo_log\obj_redo_log.vcxproj", "{9935E8A1-F3F9-41D4-BD81-AD3FD04642E9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_rm", "test\pmempool_rm\pmempool_rm.vcxproj", "{99F7F00F-1DE5-45EA-992B-64BA282FAC76}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_uuid_generate", "test\util_uuid_generate\util_uuid_generate.vcxproj", "{9A4078F8-B8E4-4EC6-A6FF-4F29DAD9CE48}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "include", "include", "{9A8482A7-BF0C-423D-8266-189456ED41F6}" ProjectSection(SolutionItems) = preProject windows\include\dirent.h = windows\include\dirent.h windows\include\endian.h = windows\include\endian.h windows\include\err.h = windows\include\err.h windows\include\features.h = windows\include\features.h windows\include\libgen.h = windows\include\libgen.h windows\include\platform.h = windows\include\platform.h include\pmemcompat.h = include\pmemcompat.h windows\include\sched.h = windows\include\sched.h windows\include\srcversion.h = windows\include\srcversion.h windows\include\strings.h = windows\include\strings.h windows\include\unistd.h = windows\include\unistd.h windows\include\win_mmap.h = windows\include\win_mmap.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_realloc", "test\obj_tx_realloc\obj_tx_realloc.vcxproj", "{9AE2DAF9-10C4-4EC3-AE52-AD5EE9C77C55}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{9C37B8CC-F810-4787-924D-65BC227091A3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_cli", "examples\libpmemobj++\map_cli\map_cli.vcxproj", "{9D1C3F29-1268-4241-BEFB-89D2859C62D3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_invalid", "test\obj_tx_invalid\obj_tx_invalid.vcxproj", "{9D9E33EB-4C24-4646-A3FB-35DA17247917}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmem", "libpmem\libpmem.vcxproj", "{9E9E3D25-2139-4A5D-9200-18148DDEAD45}" ProjectSection(ProjectDependencies) = postProject {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "examples\libpmemlog\manpage.vcxproj", "{9FF51F3E-AF36-4F45-A797-C5F03A090298}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmalloc_mt", "test\obj_pmalloc_mt\obj_pmalloc_mt.vcxproj", "{9FF62356-30B4-42A1-8DC7-45262A18DD44}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddmap", "test\tools\ddmap\ddmap.vcxproj", "{A216BF23-FC5C-4426-BF20-8568A2AA5FA0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_test", "test\libpmempool_api\libpmempool_test.vcxproj", "{A2A0FAEA-2B7C-4FC3-B904-1DB4DEACF88D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_timed_mtx", "test\obj_cpp_timed_mtx\obj_cpp_timed_mtx.vcxproj", "{A2DEA0DC-04F3-4384-BCC2-F7EE2CFD6EE7}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_nblock", "test\blk_nblock\blk_nblock.vcxproj", "{A38EFCDB-53D6-4474-97F3-0DDC6CE70D76}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {F7C6C6B6-4142-4C82-8699-4A9D8183181B} = {F7C6C6B6-4142-4C82-8699-4A9D8183181B} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_cond_var", "test\obj_cpp_cond_var\obj_cpp_cond_var.vcxproj", "{A5794EFF-8232-4E2B-B52C-908823048F54}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "out_err_win", "test\out_err_win\out_err_win.vcxproj", "{A57D9365-172E-4782-ADC6-82A594E30943}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_transaction", "test\obj_cpp_transaction\obj_cpp_transaction.vcxproj", "{A5DF0746-5496-4C29-9CCD-5FA76604BF8B}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "queue", "examples\libpmemobj++\queue\queue.vcxproj", "{A6CC801B-CF30-4703-BC54-3E21F90B787D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addlog", "examples\libpmemlog\logfile\addlog.vcxproj", "{A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_reopen", "test\cto_reopen\cto_reopen.vcxproj", "{A911D62B-9D48-4807-B183-7127F1AC7A83}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_include", "test\obj_include\obj_include.vcxproj", "{AB15A115-E429-4123-BEBF-206FBA4CF615}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_stats", "test\vmem_stats\vmem_stats.vcxproj", "{ABD4B53D-94CD-4C6A-B30A-CB6FEBA16296}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_sync", "test\libpmempool_sync\libpmempool_sync.vcxproj", "{AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signal_handle", "test\signal_handle\signal_handle.vcxproj", "{AE9E908D-BAEC-491F-9914-436B3CE35E94}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_ctl_config", "test\obj_ctl_config\obj_ctl_config.vcxproj", "{AEAA72CD-E060-417C-9CA1-49B4738384E0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "checksum", "test\checksum\checksum.vcxproj", "{AF0B7480-EBE3-486B-B0C8-134910BC9324}" ProjectSection(ProjectDependencies) = postProject {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_aligned_alloc", "test\cto_aligned_alloc\cto_aligned_alloc.vcxproj", "{B2DC2F89-0724-4110-8934-D1173BD73D44}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_transform_win", "test\libpmempool_transform_win\libpmempool_transform_win.vcxproj", "{B30C6212-A160-405A-8FE7-340E721738A2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmemwrite", "test\tools\pmemwrite\pmemwrite.vcxproj", "{B35BFA09-DE68-483B-AB61-8790E8F060A8}" ProjectSection(ProjectDependencies) = postProject {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_multiple_pools", "test\cto_multiple_pools\cto_multiple_pools.vcxproj", "{B36EE2A8-1487-47BB-B3B9-ABCB732B35F3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_memset", "test\pmem_memset\pmem_memset.vcxproj", "{B36F115C-8139-4C35-A3E7-E6BF9F3DA793}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_ctl_heap_size", "test\obj_ctl_heap_size\obj_ctl_heap_size.vcxproj", "{B379539C-E130-460D-AE82-4EBDD1A97845}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_linkedlist", "test\ex_linkedlist\ex_linkedlist.vcxproj", "{B440BB05-37A8-42EA-98D3-D83EB113E497}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_sync_win", "test\libpmempool_sync_win\libpmempool_sync_win.vcxproj", "{B6DA6617-D98F-4A4D-A7C4-A317212924BF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tools_pmemspoil", "test\pmemspoil\pmemspoil.vcxproj", "{B6F4B85D-FE55-4A1B-AE97-D4A9ECFE195F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool_win", "test\obj_pool_win\obj_pool_win.vcxproj", "{B775480C-5B32-4F64-B026-47367280EC56}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows", "windows", "{B870D8A6-12CD-4DD0-B843-833695C2310A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_list_recovery", "test\obj_list_recovery\obj_list_recovery.vcxproj", "{B887EA26-846C-4D6A-B0E4-432487506BC7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_first_next", "test\obj_first_next\obj_first_next.vcxproj", "{BABC6427-E533-4DCF-91E3-B5B2ED253F46}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_list_move", "test\obj_list_move\obj_list_move.vcxproj", "{BAE107BA-7618-4972-8188-2D3CDAAE0453}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapcli", "examples\libpmemobj\map\mapcli.vcxproj", "{BB248BAC-6E1B-433C-A254-75140A273AB5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "map", "map", "{BD6CC700-B36B-435B-BAF9-FC5AFCD766C9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctree_map", "examples\libpmemobj\tree_map\ctree_map.vcxproj", "{BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_create_win", "test\vmem_create_win\vmem_create_win.vcxproj", "{BF3B6C3A-3073-4AD4-BB41-A41047231982}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemblk", "libpmemblk", "{BFBAB433-860E-4A28-96E3-A4B7AFE3B297}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "string_store", "string_store", "{BFEDF709-A700-4769-9056-ACA934D828A8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_malloc_usable_size", "test\vmem_malloc_usable_size\vmem_malloc_usable_size.vcxproj", "{C00B4A26-6C57-4968-AED5-B45FD31A22E7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scope", "test\scope\scope.vcxproj", "{C0E811E0-8942-4CFD-A817-74D99E9E6577}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_include", "test\cto_include\cto_include.vcxproj", "{C1C505A8-634D-4640-9DB7-E2B4E59CA2D7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_list_insert", "test\obj_list_insert\obj_list_insert.vcxproj", "{C2C36D03-26EE-4BD8-8FFC-86CFE16C1218}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_strdup", "test\obj_strdup\obj_strdup.vcxproj", "{C2F94489-A483-4C44-B8A7-11A75F6AEC66}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_realloc_inplace", "test\vmem_realloc_inplace\vmem_realloc_inplace.vcxproj", "{C3A59B21-A287-4631-B4EC-F4A57D26A14F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "printlog", "examples\libpmemlog\logfile\printlog.vcxproj", "{C3CEE34C-29E0-4A22-B258-3FBAF662AA19}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_sync", "test\pmempool_sync\pmempool_sync.vcxproj", "{C5E8B8DB-2507-4904-847F-A52196B075F0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmpong", "examples\libpmemobj++\pmpong\pmpong.vcxproj", "{C6E9D8C2-D5C1-441B-95ED-378E10DC5723}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_pool_win", "test\log_pool_win\log_pool_win.vcxproj", "{C71DAF3E-9361-4723-93E2-C475D1D0C0D0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemblk", "libpmemblk", "{C721EFBD-45DC-479E-9B99-E62FCC1FC6E5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_load", "examples\libpmemblk\assetdb\asset_load.vcxproj", "{C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "examples\libvmem\manpage.vcxproj", "{C84633F5-05B1-4AC1-A074-104D1DB2A91E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_make_persistent_atomic", "test\obj_cpp_make_persistent_atomic\obj_cpp_make_persistent_atomic.vcxproj", "{C96D08A8-AFCD-4C2D-B50F-4582042FCBC1}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_is_absolute", "test\util_is_absolute\util_is_absolute.vcxproj", "{C973CD39-D63B-4F5C-BE1D-DED17388B5A4}" ProjectSection(ProjectDependencies) = postProject {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_async_postcommit", "test\obj_async_postcommit\obj_async_postcommit.vcxproj", "{CA0F317B-2474-4186-96CA-67F8D7A9D62C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "traces", "test\traces\traces.vcxproj", "{CA4BBB24-D33E-42E2-A495-F10D80DE8C1D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmembench", "benchmarks\pmembench.vcxproj", "{CB906E89-1313-4929-AFF7-86FBF1CC301F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_lane", "test\obj_lane\obj_lane.vcxproj", "{CCA9B681-D10B-45E4-98CC-531503D2EDE8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_create_error", "test\vmem_create_error\vmem_create_error.vcxproj", "{CD4B9690-7A06-4F7A-8492-9336979EE7E9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_multiple_pools", "test\vmem_multiple_pools\vmem_multiple_pools.vcxproj", "{CD7A18D5-55D9-4922-A000-FFAA08ABB006}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_check", "test\pmempool_check\pmempool_check.vcxproj", "{CDD9DFC6-5C3D-42F7-B822-FE29A1C21752}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libut", "test\unittest\libut.vcxproj", "{CE3F2DFB-8470-4802-AD37-21CAF6CB2681}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool", "libpmempool\libpmempool.vcxproj", "{CF9A0883-6334-44C7-AC29-349468C78E27}" ProjectSection(ProjectDependencies) = postProject {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_copy", "examples\libpmem\simple_copy.vcxproj", "{D062166F-0EC7-4C13-A772-0C7157EEFE41}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tools_pmemobjcli", "test\pmemobjcli\pmemobjcli.vcxproj", "{D28F5FF6-8401-4E0D-94F9-3A1FD7ED64E3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmemobjcli", "test\tools\pmemobjcli\pmemobjcli.vcxproj", "{D2C30C7E-A7D3-487A-956E-418CECAFFE8E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fifo", "examples\libpmemobj\linkedlist\fifo.vcxproj", "{D3A99F36-4B72-4766-ABCD-CCEDC26DD139}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmempool_help", "test\pmempool_help\pmempool_help.vcxproj", "{D4035736-1AD6-4100-9FA9-A8A0C1DAE0C7}" EndProject Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "PMDK_setup", "windows\setup\setup.vdproj", "{D5093EC2-5B5A-4D79-842C-6A1481E9C989}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_file_create", "test\util_file_create\util_file_create.vcxproj", "{D829DB63-E046-474D-8EA3-43A6659294D8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_libpmemlog", "test\ex_libpmemlog\ex_libpmemlog.vcxproj", "{D8317F1D-7A70-4A39-977A-EAB05A04A87B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_lock", "test\obj_tx_lock\obj_tx_lock.vcxproj", "{D88187D2-1977-4C5F-B0CD-83C69BD6C1BC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hashmap_tx", "examples\libpmemobj\hashmap\hashmap_tx.vcxproj", "{D93A2683-6D99-4F18-B378-91195D23E007}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cto_pool", "test\cto_pool\cto_pool.vcxproj", "{DB12B063-B09B-4D74-B293-F00A72D07BB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blk_recovery", "test\blk_recovery\blk_recovery.vcxproj", "{DB68AB21-510B-4BA1-9E6F-E5731D8647BC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_ptr", "test\obj_cpp_ptr\obj_cpp_ptr.vcxproj", "{DFEBEBAA-9624-445C-82A0-93363E22D806}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{E23BB160-006E-44F2-8FB4-3A2240BBC20C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "string_store_tx_type", "string_store_tx_type", "{E3229AF7-1FA2-4632-BB0B-B74F709F1A33}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_is_pmem", "test\pmem_is_pmem\pmem_is_pmem.vcxproj", "{E4E2EC33-7902-45D0-9C3C-ADBAFA46874A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_poolset_foreach", "test\util_poolset_foreach\util_poolset_foreach.vcxproj", "{E648732D-78FA-427A-928C-9A59222D37B7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_pool_lock", "test\log_pool_lock\log_pool_lock.vcxproj", "{E68DEB59-C709-4945-AF80-EEBCADDED944}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_constructor", "test\obj_constructor\obj_constructor.vcxproj", "{E7691F81-86EF-467D-82E1-F5B9416386F9}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_ctl", "test\obj_ctl\obj_ctl.vcxproj", "{E796AA20-D664-4D05-ABD9-C93A4FBE3E5C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_recovery", "test\log_recovery\log_recovery.vcxproj", "{E901B756-EA72-4B8D-967F-85F109D0D1DE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_locks", "test\obj_tx_locks\obj_tx_locks.vcxproj", "{E9E079D6-25BF-46E3-8075-7D733303DD59}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libvmem", "libvmem", "{EA0D2458-5FCD-4DAB-B07D-229327B98BEB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_map_flog", "test\libpmempool_map_flog\libpmempool_map_flog.vcxproj", "{ED2A831F-4AAF-4CF7-A953-3C45B0EC1BE6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "examples\libpmemobj\manpage.vcxproj", "{EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{F09A0864-9221-47AD-872F-D4538104D747}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_is_poolset", "test\util_is_poolset\util_is_poolset.vcxproj", "{F0B613C4-1D9A-4259-BD0E-C1B9FF2AA3A0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_signal", "test\win_signal\win_signal.vcxproj", "{F13108C4-4C86-4D56-A317-A4E5892A8AF7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_pool_win", "test\obj_cpp_pool_win\obj_cpp_pool_win.vcxproj", "{F322ED35-A389-4B65-AC8A-E25F1337DBCC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_tx_add_range", "test\obj_tx_add_range\obj_tx_add_range.vcxproj", "{F3E5650D-834E-45E6-90C7-3FC2AA954929}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemobj", "libpmemobj", "{F42C09CD-ABA5-4DA9-8383-5EA40FA4D763}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "writer", "examples\libpmemobj\string_store\writer.vcxproj", "{F5D850C9-D353-4B84-99BC-E336C231018C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hashmap_atomic", "examples\libpmemobj\hashmap\hashmap_atomic.vcxproj", "{F5E2F6C4-19BA-497A-B754-232E469BE647}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ex_libpmemobj", "test\ex_libpmemobj\ex_libpmemobj.vcxproj", "{F63FB47F-1DCE-48E5-9CBD-F3E0A354472B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmemblk", "libpmemblk\libpmemblk.vcxproj", "{F7C6C6B6-4142-4C82-8699-4A9D8183181B}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {492BAA3D-0D5D-478E-9765-500463AE69AA} = {492BAA3D-0D5D-478E-9765-500463AE69AA} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmem", "libpmem", "{F8373EDD-1B9E-462D-BF23-55638E23E98B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{F8CCA5AE-2D75-4C79-BEAB-2588CD5956C8}" ProjectSection(SolutionItems) = preProject ..\appveyor.yml = ..\appveyor.yml ..\utils\CHECK_WHITESPACE.PS1 = ..\utils\CHECK_WHITESPACE.PS1 ..\utils\CREATE-ZIP.PS1 = ..\utils\CREATE-ZIP.PS1 ..\utils\cstyle = ..\utils\cstyle ..\utils\CSTYLE.ps1 = ..\utils\CSTYLE.ps1 EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_transform", "test\libpmempool_transform\libpmempool_transform.vcxproj", "{FB2D2B18-E616-4639-8593-0E1AF2DA01A8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_pool_primitives", "test\obj_cpp_pool_primitives\obj_cpp_pool_primitives.vcxproj", "{FB6AFFAA-0279-41F7-A698-F81C90BBD987}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_basic", "test\log_basic\log_basic.vcxproj", "{FBB77433-639E-42DC-9355-EA94CAE294D2}" ProjectSection(ProjectDependencies) = postProject {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {0B1818EB-BDC8-4865-964F-DB8BF05CFD86} = {0B1818EB-BDC8-4865-964F-DB8BF05CFD86} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "examples\libpmem\manpage.vcxproj", "{FCD0587A-4504-4F5E-8E9C-468CC03D250A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_vec", "test\util_vec\util_vec.vcxproj", "{FD726AA3-D4FA-4597-B435-08CC7752888C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_cpp_p_ext", "test\obj_cpp_p_ext\obj_cpp_p_ext.vcxproj", "{FD86DEA2-449E-44CD-A014-BFC30ED3FDF2}" ProjectSection(ProjectDependencies) = postProject {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {9E9E3D25-2139-4A5D-9200-18148DDEAD45} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_mmap_fixed", "test\win_mmap_fixed\win_mmap_fixed.vcxproj", "{FEA09B48-34C2-4963-8A5A-F97BDA136D72}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmem_check", "test\vmem_check\vmem_check.vcxproj", "{FF374D62-CBCF-401E-9A02-1D3DB8BE16E4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_list_remove", "test\obj_list_remove\obj_list_remove.vcxproj", "{FF6E5B0C-DC00-4C93-B9C2-63D1E858BA79}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Debug|x64.ActiveCfg = Debug|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Debug|x64.Build.0 = Debug|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Release|x64.ActiveCfg = Release|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Release|x64.Build.0 = Release|x64 {025E7D51-41F2-4CBA-956E-C37A4443DB1B}.Debug|x64.ActiveCfg = Debug|x64 {025E7D51-41F2-4CBA-956E-C37A4443DB1B}.Debug|x64.Build.0 = Debug|x64 {025E7D51-41F2-4CBA-956E-C37A4443DB1B}.Release|x64.ActiveCfg = Release|x64 {025E7D51-41F2-4CBA-956E-C37A4443DB1B}.Release|x64.Build.0 = Release|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Debug|x64.ActiveCfg = Debug|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Debug|x64.Build.0 = Debug|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Release|x64.ActiveCfg = Release|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Release|x64.Build.0 = Release|x64 {02BC3B44-C7F1-4793-86C1-6F36CA8A7F53}.Debug|x64.ActiveCfg = Debug|x64 {02BC3B44-C7F1-4793-86C1-6F36CA8A7F53}.Debug|x64.Build.0 = Debug|x64 {02BC3B44-C7F1-4793-86C1-6F36CA8A7F53}.Release|x64.ActiveCfg = Release|x64 {0388E945-A655-41A7-AF27-8981CEE0E49A}.Debug|x64.ActiveCfg = Debug|x64 {0388E945-A655-41A7-AF27-8981CEE0E49A}.Debug|x64.Build.0 = Debug|x64 {0388E945-A655-41A7-AF27-8981CEE0E49A}.Release|x64.ActiveCfg = Release|x64 {0388E945-A655-41A7-AF27-8981CEE0E49A}.Release|x64.Build.0 = Release|x64 {04345B7D-B0A1-405B-8BB2-5B98A3400FEF}.Debug|x64.ActiveCfg = Debug|x64 {04345B7D-B0A1-405B-8BB2-5B98A3400FEF}.Debug|x64.Build.0 = Debug|x64 {04345B7D-B0A1-405B-8BB2-5B98A3400FEF}.Release|x64.ActiveCfg = Release|x64 {04345B7D-B0A1-405B-8BB2-5B98A3400FEF}.Release|x64.Build.0 = Release|x64 {0529575C-F6E8-44FD-BB82-82A29948D0F2}.Debug|x64.ActiveCfg = Debug|x64 {0529575C-F6E8-44FD-BB82-82A29948D0F2}.Debug|x64.Build.0 = Debug|x64 {0529575C-F6E8-44FD-BB82-82A29948D0F2}.Release|x64.ActiveCfg = Release|x64 {0529575C-F6E8-44FD-BB82-82A29948D0F2}.Release|x64.Build.0 = Release|x64 {063037B2-CA35-4520-811C-19D9C4ED891E}.Debug|x64.ActiveCfg = Debug|x64 {063037B2-CA35-4520-811C-19D9C4ED891E}.Debug|x64.Build.0 = Debug|x64 {063037B2-CA35-4520-811C-19D9C4ED891E}.Release|x64.ActiveCfg = Release|x64 {063037B2-CA35-4520-811C-19D9C4ED891E}.Release|x64.Build.0 = Release|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Debug|x64.ActiveCfg = Debug|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Debug|x64.Build.0 = Debug|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Release|x64.ActiveCfg = Release|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Release|x64.Build.0 = Release|x64 {06FCFDE9-8C88-4B7D-B87A-47953DB203C9}.Debug|x64.ActiveCfg = Debug|x64 {06FCFDE9-8C88-4B7D-B87A-47953DB203C9}.Debug|x64.Build.0 = Debug|x64 {06FCFDE9-8C88-4B7D-B87A-47953DB203C9}.Release|x64.ActiveCfg = Release|x64 {06FCFDE9-8C88-4B7D-B87A-47953DB203C9}.Release|x64.Build.0 = Release|x64 {0703E813-9CC8-4DEA-AA33-42B099CD172D}.Debug|x64.ActiveCfg = Debug|x64 {0703E813-9CC8-4DEA-AA33-42B099CD172D}.Debug|x64.Build.0 = Debug|x64 {0703E813-9CC8-4DEA-AA33-42B099CD172D}.Release|x64.ActiveCfg = Release|x64 {0703E813-9CC8-4DEA-AA33-42B099CD172D}.Release|x64.Build.0 = Release|x64 {07A153D9-DF17-4DE8-A3C2-EBF171B961AE}.Debug|x64.ActiveCfg = Debug|x64 {07A153D9-DF17-4DE8-A3C2-EBF171B961AE}.Debug|x64.Build.0 = Debug|x64 {07A153D9-DF17-4DE8-A3C2-EBF171B961AE}.Release|x64.ActiveCfg = Release|x64 {07A153D9-DF17-4DE8-A3C2-EBF171B961AE}.Release|x64.Build.0 = Release|x64 {08762559-E9DF-475B-BA99-49F4B5A1D80B}.Debug|x64.ActiveCfg = Debug|x64 {08762559-E9DF-475B-BA99-49F4B5A1D80B}.Debug|x64.Build.0 = Debug|x64 {08762559-E9DF-475B-BA99-49F4B5A1D80B}.Release|x64.ActiveCfg = Release|x64 {08762559-E9DF-475B-BA99-49F4B5A1D80B}.Release|x64.Build.0 = Release|x64 {08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Debug|x64.ActiveCfg = Debug|x64 {08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Debug|x64.Build.0 = Debug|x64 {08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Release|x64.ActiveCfg = Release|x64 {08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Release|x64.Build.0 = Release|x64 {0A049EAD-652F-4E20-8026-90FD99AEE77A}.Debug|x64.ActiveCfg = Debug|x64 {0A049EAD-652F-4E20-8026-90FD99AEE77A}.Debug|x64.Build.0 = Debug|x64 {0A049EAD-652F-4E20-8026-90FD99AEE77A}.Release|x64.ActiveCfg = Release|x64 {0A049EAD-652F-4E20-8026-90FD99AEE77A}.Release|x64.Build.0 = Release|x64 {0B1818EB-BDC8-4865-964F-DB8BF05CFD86}.Debug|x64.ActiveCfg = Debug|x64 {0B1818EB-BDC8-4865-964F-DB8BF05CFD86}.Debug|x64.Build.0 = Debug|x64 {0B1818EB-BDC8-4865-964F-DB8BF05CFD86}.Release|x64.ActiveCfg = Release|x64 {0B1818EB-BDC8-4865-964F-DB8BF05CFD86}.Release|x64.Build.0 = Release|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Debug|x64.ActiveCfg = Debug|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Debug|x64.Build.0 = Debug|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Release|x64.ActiveCfg = Release|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Release|x64.Build.0 = Release|x64 {0CDCEB97-3270-4939-A290-EA2D3BE34B0C}.Debug|x64.ActiveCfg = Debug|x64 {0CDCEB97-3270-4939-A290-EA2D3BE34B0C}.Debug|x64.Build.0 = Debug|x64 {0CDCEB97-3270-4939-A290-EA2D3BE34B0C}.Release|x64.ActiveCfg = Release|x64 {0CDCEB97-3270-4939-A290-EA2D3BE34B0C}.Release|x64.Build.0 = Release|x64 {0DC1B184-C814-448F-8B5F-CFFA6F05156C}.Debug|x64.ActiveCfg = Debug|x64 {0DC1B184-C814-448F-8B5F-CFFA6F05156C}.Debug|x64.Build.0 = Debug|x64 {0DC1B184-C814-448F-8B5F-CFFA6F05156C}.Release|x64.ActiveCfg = Release|x64 {0DC1B184-C814-448F-8B5F-CFFA6F05156C}.Release|x64.Build.0 = Release|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Debug|x64.ActiveCfg = Debug|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Debug|x64.Build.0 = Debug|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Release|x64.ActiveCfg = Release|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Release|x64.Build.0 = Release|x64 {10469175-EEF7-44A0-9961-AC4E45EFD800}.Debug|x64.ActiveCfg = Debug|x64 {10469175-EEF7-44A0-9961-AC4E45EFD800}.Debug|x64.Build.0 = Debug|x64 {10469175-EEF7-44A0-9961-AC4E45EFD800}.Release|x64.ActiveCfg = Release|x64 {10469175-EEF7-44A0-9961-AC4E45EFD800}.Release|x64.Build.0 = Release|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Debug|x64.ActiveCfg = Debug|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Debug|x64.Build.0 = Debug|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Release|x64.ActiveCfg = Release|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Release|x64.Build.0 = Release|x64 {11E158AE-C85A-4A6E-B66A-ED2994709276}.Debug|x64.ActiveCfg = Debug|x64 {11E158AE-C85A-4A6E-B66A-ED2994709276}.Debug|x64.Build.0 = Debug|x64 {11E158AE-C85A-4A6E-B66A-ED2994709276}.Release|x64.ActiveCfg = Release|x64 {11E158AE-C85A-4A6E-B66A-ED2994709276}.Release|x64.Build.0 = Release|x64 {12A1A3EF-202C-4DD0-9B5A-F5126CAB078F}.Debug|x64.ActiveCfg = Debug|x64 {12A1A3EF-202C-4DD0-9B5A-F5126CAB078F}.Debug|x64.Build.0 = Debug|x64 {12A1A3EF-202C-4DD0-9B5A-F5126CAB078F}.Release|x64.ActiveCfg = Release|x64 {12A1A3EF-202C-4DD0-9B5A-F5126CAB078F}.Release|x64.Build.0 = Release|x64 {1464398A-100F-4518-BDB9-939A6362B6CF}.Debug|x64.ActiveCfg = Debug|x64 {1464398A-100F-4518-BDB9-939A6362B6CF}.Debug|x64.Build.0 = Debug|x64 {1464398A-100F-4518-BDB9-939A6362B6CF}.Release|x64.ActiveCfg = Release|x64 {1464398A-100F-4518-BDB9-939A6362B6CF}.Release|x64.Build.0 = Release|x64 {179BEB5A-2C90-44F5-A734-FA756A5E668C}.Debug|x64.ActiveCfg = Debug|x64 {179BEB5A-2C90-44F5-A734-FA756A5E668C}.Debug|x64.Build.0 = Debug|x64 {179BEB5A-2C90-44F5-A734-FA756A5E668C}.Release|x64.ActiveCfg = Release|x64 {179BEB5A-2C90-44F5-A734-FA756A5E668C}.Release|x64.Build.0 = Release|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Debug|x64.ActiveCfg = Debug|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Debug|x64.Build.0 = Debug|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Release|x64.ActiveCfg = Release|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Release|x64.Build.0 = Release|x64 {18E90E1A-F2E0-40DF-9900-A14E560C9EB4}.Debug|x64.ActiveCfg = Debug|x64 {18E90E1A-F2E0-40DF-9900-A14E560C9EB4}.Debug|x64.Build.0 = Debug|x64 {18E90E1A-F2E0-40DF-9900-A14E560C9EB4}.Release|x64.ActiveCfg = Release|x64 {18E90E1A-F2E0-40DF-9900-A14E560C9EB4}.Release|x64.Build.0 = Release|x64 {1B871BA2-3F70-4BC9-9DF4-725EB07F6628}.Debug|x64.ActiveCfg = Debug|x64 {1B871BA2-3F70-4BC9-9DF4-725EB07F6628}.Debug|x64.Build.0 = Debug|x64 {1B871BA2-3F70-4BC9-9DF4-725EB07F6628}.Release|x64.ActiveCfg = Release|x64 {1B871BA2-3F70-4BC9-9DF4-725EB07F6628}.Release|x64.Build.0 = Release|x64 {1B9B0D6D-E530-44A6-ADAE-09EA2BDC47DE}.Debug|x64.ActiveCfg = Debug|x64 {1B9B0D6D-E530-44A6-ADAE-09EA2BDC47DE}.Debug|x64.Build.0 = Debug|x64 {1B9B0D6D-E530-44A6-ADAE-09EA2BDC47DE}.Release|x64.ActiveCfg = Release|x64 {1B9B0D6D-E530-44A6-ADAE-09EA2BDC47DE}.Release|x64.Build.0 = Release|x64 {1BA340EC-B0B2-438D-A47C-27F86F604133}.Debug|x64.ActiveCfg = Debug|x64 {1BA340EC-B0B2-438D-A47C-27F86F604133}.Debug|x64.Build.0 = Debug|x64 {1BA340EC-B0B2-438D-A47C-27F86F604133}.Release|x64.ActiveCfg = Release|x64 {1BA340EC-B0B2-438D-A47C-27F86F604133}.Release|x64.Build.0 = Release|x64 {1BAA1617-93AE-4196-8A1A-BD492FB18AEF}.Debug|x64.ActiveCfg = Debug|x64 {1BAA1617-93AE-4196-8A1A-BD492FB18AEF}.Debug|x64.Build.0 = Debug|x64 {1BAA1617-93AE-4196-8A1A-BD492FB18AEF}.Release|x64.ActiveCfg = Release|x64 {1BAA1617-93AE-4196-8A1A-BD492FB18AEF}.Release|x64.Build.0 = Release|x64 {1E564DB1-0687-4CC4-BAE5-453F93052FDA}.Debug|x64.ActiveCfg = Debug|x64 {1E564DB1-0687-4CC4-BAE5-453F93052FDA}.Debug|x64.Build.0 = Debug|x64 {1E564DB1-0687-4CC4-BAE5-453F93052FDA}.Release|x64.ActiveCfg = Release|x64 {1E564DB1-0687-4CC4-BAE5-453F93052FDA}.Release|x64.Build.0 = Release|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Debug|x64.ActiveCfg = Debug|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Debug|x64.Build.0 = Debug|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Release|x64.ActiveCfg = Release|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Release|x64.Build.0 = Release|x64 {1F2E1C51-2B14-4047-BE6D-52E00FC3C780}.Debug|x64.ActiveCfg = Debug|x64 {1F2E1C51-2B14-4047-BE6D-52E00FC3C780}.Debug|x64.Build.0 = Debug|x64 {1F2E1C51-2B14-4047-BE6D-52E00FC3C780}.Release|x64.ActiveCfg = Release|x64 {1F2E1C51-2B14-4047-BE6D-52E00FC3C780}.Release|x64.Build.0 = Release|x64 {21991E84-7859-420E-ADDA-1D058E787F06}.Debug|x64.ActiveCfg = Debug|x64 {21991E84-7859-420E-ADDA-1D058E787F06}.Debug|x64.Build.0 = Debug|x64 {21991E84-7859-420E-ADDA-1D058E787F06}.Release|x64.ActiveCfg = Release|x64 {21991E84-7859-420E-ADDA-1D058E787F06}.Release|x64.Build.0 = Release|x64 {22DCCD3E-79FF-4F66-A9AA-D033A7671B94}.Debug|x64.ActiveCfg = Debug|x64 {22DCCD3E-79FF-4F66-A9AA-D033A7671B94}.Debug|x64.Build.0 = Debug|x64 {22DCCD3E-79FF-4F66-A9AA-D033A7671B94}.Release|x64.ActiveCfg = Release|x64 {22DCCD3E-79FF-4F66-A9AA-D033A7671B94}.Release|x64.Build.0 = Release|x64 {2498FCDA-E2CC-43EF-9A35-8CD63F253171}.Debug|x64.ActiveCfg = Debug|x64 {2498FCDA-E2CC-43EF-9A35-8CD63F253171}.Debug|x64.Build.0 = Debug|x64 {2498FCDA-E2CC-43EF-9A35-8CD63F253171}.Release|x64.ActiveCfg = Release|x64 {2498FCDA-E2CC-43EF-9A35-8CD63F253171}.Release|x64.Build.0 = Release|x64 {25B5C601-03D7-4861-9C0F-7F0453B04227}.Debug|x64.ActiveCfg = Debug|x64 {25B5C601-03D7-4861-9C0F-7F0453B04227}.Debug|x64.Build.0 = Debug|x64 {25B5C601-03D7-4861-9C0F-7F0453B04227}.Release|x64.ActiveCfg = Release|x64 {25B5C601-03D7-4861-9C0F-7F0453B04227}.Release|x64.Build.0 = Release|x64 {26135DD1-8BB0-4217-A4DC-C1F232F35BA2}.Debug|x64.ActiveCfg = Debug|x64 {26135DD1-8BB0-4217-A4DC-C1F232F35BA2}.Debug|x64.Build.0 = Debug|x64 {26135DD1-8BB0-4217-A4DC-C1F232F35BA2}.Release|x64.ActiveCfg = Release|x64 {26135DD1-8BB0-4217-A4DC-C1F232F35BA2}.Release|x64.Build.0 = Release|x64 {26166DF1-3C94-44AF-9075-BA31DCD2F6BB}.Debug|x64.ActiveCfg = Debug|x64 {26166DF1-3C94-44AF-9075-BA31DCD2F6BB}.Debug|x64.Build.0 = Debug|x64 {26166DF1-3C94-44AF-9075-BA31DCD2F6BB}.Release|x64.ActiveCfg = Release|x64 {26166DF1-3C94-44AF-9075-BA31DCD2F6BB}.Release|x64.Build.0 = Release|x64 {26D24B3D-22CE-44EB-AA21-2BF594F80520}.Debug|x64.ActiveCfg = Debug|x64 {26D24B3D-22CE-44EB-AA21-2BF594F80520}.Debug|x64.Build.0 = Debug|x64 {26D24B3D-22CE-44EB-AA21-2BF594F80520}.Release|x64.ActiveCfg = Release|x64 {26D24B3D-22CE-44EB-AA21-2BF594F80520}.Release|x64.Build.0 = Release|x64 {27FA11C6-431D-41D1-A417-FAB7C4F93DCA}.Debug|x64.ActiveCfg = Debug|x64 {27FA11C6-431D-41D1-A417-FAB7C4F93DCA}.Debug|x64.Build.0 = Debug|x64 {27FA11C6-431D-41D1-A417-FAB7C4F93DCA}.Release|x64.ActiveCfg = Release|x64 {27FA11C6-431D-41D1-A417-FAB7C4F93DCA}.Release|x64.Build.0 = Release|x64 {296F3C5D-3951-423E-8E2F-FD4A37958C72}.Debug|x64.ActiveCfg = Debug|x64 {296F3C5D-3951-423E-8E2F-FD4A37958C72}.Debug|x64.Build.0 = Debug|x64 {296F3C5D-3951-423E-8E2F-FD4A37958C72}.Release|x64.ActiveCfg = Release|x64 {296F3C5D-3951-423E-8E2F-FD4A37958C72}.Release|x64.Build.0 = Release|x64 {29D9376B-DC36-4940-83F1-A7CBE38A2103}.Debug|x64.ActiveCfg = Debug|x64 {29D9376B-DC36-4940-83F1-A7CBE38A2103}.Debug|x64.Build.0 = Debug|x64 {29D9376B-DC36-4940-83F1-A7CBE38A2103}.Release|x64.ActiveCfg = Release|x64 {29D9376B-DC36-4940-83F1-A7CBE38A2103}.Release|x64.Build.0 = Release|x64 {2A1D6AF2-7336-4966-A4B3-0BE9A24BAE00}.Debug|x64.ActiveCfg = Debug|x64 {2A1D6AF2-7336-4966-A4B3-0BE9A24BAE00}.Debug|x64.Build.0 = Debug|x64 {2A1D6AF2-7336-4966-A4B3-0BE9A24BAE00}.Release|x64.ActiveCfg = Release|x64 {2A1D6AF2-7336-4966-A4B3-0BE9A24BAE00}.Release|x64.Build.0 = Release|x64 {2B1A5104-A324-4D02-B5C7-D021FB8F880C}.Debug|x64.ActiveCfg = Debug|x64 {2B1A5104-A324-4D02-B5C7-D021FB8F880C}.Debug|x64.Build.0 = Debug|x64 {2B1A5104-A324-4D02-B5C7-D021FB8F880C}.Release|x64.ActiveCfg = Release|x64 {2B1A5104-A324-4D02-B5C7-D021FB8F880C}.Release|x64.Build.0 = Release|x64 {2B7772E6-9DAA-4F38-B0BC-7B2399366325}.Debug|x64.ActiveCfg = Debug|x64 {2B7772E6-9DAA-4F38-B0BC-7B2399366325}.Debug|x64.Build.0 = Debug|x64 {2B7772E6-9DAA-4F38-B0BC-7B2399366325}.Release|x64.ActiveCfg = Release|x64 {2B7772E6-9DAA-4F38-B0BC-7B2399366325}.Release|x64.Build.0 = Release|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Debug|x64.ActiveCfg = Debug|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Debug|x64.Build.0 = Debug|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Release|x64.ActiveCfg = Release|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Release|x64.Build.0 = Release|x64 {2DE6B085-3C19-49B1-894A-AD9376000E09}.Debug|x64.ActiveCfg = Debug|x64 {2DE6B085-3C19-49B1-894A-AD9376000E09}.Debug|x64.Build.0 = Debug|x64 {2DE6B085-3C19-49B1-894A-AD9376000E09}.Release|x64.ActiveCfg = Release|x64 {2DE6B085-3C19-49B1-894A-AD9376000E09}.Release|x64.Build.0 = Release|x64 {2E7E8487-0BB0-4E8A-8672-ED8ABD80D468}.Debug|x64.ActiveCfg = Debug|x64 {2E7E8487-0BB0-4E8A-8672-ED8ABD80D468}.Debug|x64.Build.0 = Debug|x64 {2E7E8487-0BB0-4E8A-8672-ED8ABD80D468}.Release|x64.ActiveCfg = Release|x64 {2E7E8487-0BB0-4E8A-8672-ED8ABD80D468}.Release|x64.Build.0 = Release|x64 {2ED26FDA-3C4E-4514-B387-5E77C302FF71}.Debug|x64.ActiveCfg = Debug|x64 {2ED26FDA-3C4E-4514-B387-5E77C302FF71}.Debug|x64.Build.0 = Debug|x64 {2ED26FDA-3C4E-4514-B387-5E77C302FF71}.Release|x64.ActiveCfg = Release|x64 {2ED26FDA-3C4E-4514-B387-5E77C302FF71}.Release|x64.Build.0 = Release|x64 {2EFFC590-BF5E-46A2-AF04-E67E1D571D2E}.Debug|x64.ActiveCfg = Debug|x64 {2EFFC590-BF5E-46A2-AF04-E67E1D571D2E}.Debug|x64.Build.0 = Debug|x64 {2EFFC590-BF5E-46A2-AF04-E67E1D571D2E}.Release|x64.ActiveCfg = Release|x64 {2EFFC590-BF5E-46A2-AF04-E67E1D571D2E}.Release|x64.Build.0 = Release|x64 {3142CB13-CADA-48D3-9A25-E6ACB243760A}.Debug|x64.ActiveCfg = Debug|x64 {3142CB13-CADA-48D3-9A25-E6ACB243760A}.Debug|x64.Build.0 = Debug|x64 {3142CB13-CADA-48D3-9A25-E6ACB243760A}.Release|x64.ActiveCfg = Release|x64 {3142CB13-CADA-48D3-9A25-E6ACB243760A}.Release|x64.Build.0 = Release|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Debug|x64.ActiveCfg = Debug|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Debug|x64.Build.0 = Debug|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Release|x64.ActiveCfg = Release|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Release|x64.Build.0 = Release|x64 {3B23831B-E5DE-4A62-9D0B-27D0D9F293F4}.Debug|x64.ActiveCfg = Debug|x64 {3B23831B-E5DE-4A62-9D0B-27D0D9F293F4}.Debug|x64.Build.0 = Debug|x64 {3B23831B-E5DE-4A62-9D0B-27D0D9F293F4}.Release|x64.ActiveCfg = Release|x64 {3B23831B-E5DE-4A62-9D0B-27D0D9F293F4}.Release|x64.Build.0 = Release|x64 {3BAB8FDF-42F7-4D46-AA10-E282FD41B9F2}.Debug|x64.ActiveCfg = Debug|x64 {3BAB8FDF-42F7-4D46-AA10-E282FD41B9F2}.Debug|x64.Build.0 = Debug|x64 {3BAB8FDF-42F7-4D46-AA10-E282FD41B9F2}.Release|x64.ActiveCfg = Release|x64 {3BAB8FDF-42F7-4D46-AA10-E282FD41B9F2}.Release|x64.Build.0 = Release|x64 {3CF270CD-0F56-48E3-AD84-82F369C568BF}.Debug|x64.ActiveCfg = Debug|x64 {3CF270CD-0F56-48E3-AD84-82F369C568BF}.Debug|x64.Build.0 = Debug|x64 {3CF270CD-0F56-48E3-AD84-82F369C568BF}.Release|x64.ActiveCfg = Release|x64 {3CF270CD-0F56-48E3-AD84-82F369C568BF}.Release|x64.Build.0 = Release|x64 {3D9A580B-5F0F-434F-B4D6-228B8E7ADAA5}.Debug|x64.ActiveCfg = Debug|x64 {3D9A580B-5F0F-434F-B4D6-228B8E7ADAA5}.Debug|x64.Build.0 = Debug|x64 {3D9A580B-5F0F-434F-B4D6-228B8E7ADAA5}.Release|x64.ActiveCfg = Release|x64 {3D9A580B-5F0F-434F-B4D6-228B8E7ADAA5}.Release|x64.Build.0 = Release|x64 {3DEB4FBF-638D-4588-A510-E9A77FF75BB1}.Debug|x64.ActiveCfg = Debug|x64 {3DEB4FBF-638D-4588-A510-E9A77FF75BB1}.Debug|x64.Build.0 = Debug|x64 {3DEB4FBF-638D-4588-A510-E9A77FF75BB1}.Release|x64.ActiveCfg = Release|x64 {3DEB4FBF-638D-4588-A510-E9A77FF75BB1}.Release|x64.Build.0 = Release|x64 {3EC30D6A-BDA4-4971-879A-8814204EAE31}.Debug|x64.ActiveCfg = Debug|x64 {3EC30D6A-BDA4-4971-879A-8814204EAE31}.Debug|x64.Build.0 = Debug|x64 {3EC30D6A-BDA4-4971-879A-8814204EAE31}.Release|x64.ActiveCfg = Release|x64 {3EC30D6A-BDA4-4971-879A-8814204EAE31}.Release|x64.Build.0 = Release|x64 {3ECCB0F1-3ADF-486A-91C5-79DF0FC22F78}.Debug|x64.ActiveCfg = Debug|x64 {3ECCB0F1-3ADF-486A-91C5-79DF0FC22F78}.Debug|x64.Build.0 = Debug|x64 {3ECCB0F1-3ADF-486A-91C5-79DF0FC22F78}.Release|x64.ActiveCfg = Release|x64 {3ECCB0F1-3ADF-486A-91C5-79DF0FC22F78}.Release|x64.Build.0 = Release|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Debug|x64.ActiveCfg = Debug|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Debug|x64.Build.0 = Debug|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Release|x64.ActiveCfg = Release|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Release|x64.Build.0 = Release|x64 {40DC66AD-F66D-4194-B9A4-A3A2222516FE}.Debug|x64.ActiveCfg = Debug|x64 {40DC66AD-F66D-4194-B9A4-A3A2222516FE}.Debug|x64.Build.0 = Debug|x64 {40DC66AD-F66D-4194-B9A4-A3A2222516FE}.Release|x64.ActiveCfg = Release|x64 {40DC66AD-F66D-4194-B9A4-A3A2222516FE}.Release|x64.Build.0 = Release|x64 {42CCEF95-5ADD-460C-967E-DD5B2C744943}.Debug|x64.ActiveCfg = Debug|x64 {42CCEF95-5ADD-460C-967E-DD5B2C744943}.Debug|x64.Build.0 = Debug|x64 {42CCEF95-5ADD-460C-967E-DD5B2C744943}.Release|x64.ActiveCfg = Release|x64 {42CCEF95-5ADD-460C-967E-DD5B2C744943}.Release|x64.Build.0 = Release|x64 {433F7840-C597-4950-84C9-E4FF7DF6A298}.Debug|x64.ActiveCfg = Debug|x64 {433F7840-C597-4950-84C9-E4FF7DF6A298}.Debug|x64.Build.0 = Debug|x64 {433F7840-C597-4950-84C9-E4FF7DF6A298}.Release|x64.ActiveCfg = Release|x64 {433F7840-C597-4950-84C9-E4FF7DF6A298}.Release|x64.Build.0 = Release|x64 {4850F425-9128-4E91-973C-5AE7BD97395B}.Debug|x64.ActiveCfg = Debug|x64 {4850F425-9128-4E91-973C-5AE7BD97395B}.Debug|x64.Build.0 = Debug|x64 {4850F425-9128-4E91-973C-5AE7BD97395B}.Release|x64.ActiveCfg = Release|x64 {4850F425-9128-4E91-973C-5AE7BD97395B}.Release|x64.Build.0 = Release|x64 {48A3AE10-200B-454E-9D82-EC1A88CF1151}.Debug|x64.ActiveCfg = Debug|x64 {48A3AE10-200B-454E-9D82-EC1A88CF1151}.Debug|x64.Build.0 = Debug|x64 {48A3AE10-200B-454E-9D82-EC1A88CF1151}.Release|x64.ActiveCfg = Release|x64 {48A3AE10-200B-454E-9D82-EC1A88CF1151}.Release|x64.Build.0 = Release|x64 {492BAA3D-0D5D-478E-9765-500463AE69AA}.Debug|x64.ActiveCfg = Debug|x64 {492BAA3D-0D5D-478E-9765-500463AE69AA}.Debug|x64.Build.0 = Debug|x64 {492BAA3D-0D5D-478E-9765-500463AE69AA}.Release|x64.ActiveCfg = Release|x64 {492BAA3D-0D5D-478E-9765-500463AE69AA}.Release|x64.Build.0 = Release|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Debug|x64.ActiveCfg = Debug|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Debug|x64.Build.0 = Debug|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Release|x64.ActiveCfg = Release|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Release|x64.Build.0 = Release|x64 {4A3CDA9F-55C2-455E-8E82-1FAAAA2245C5}.Debug|x64.ActiveCfg = Debug|x64 {4A3CDA9F-55C2-455E-8E82-1FAAAA2245C5}.Debug|x64.Build.0 = Debug|x64 {4A3CDA9F-55C2-455E-8E82-1FAAAA2245C5}.Release|x64.ActiveCfg = Release|x64 {4A3CDA9F-55C2-455E-8E82-1FAAAA2245C5}.Release|x64.Build.0 = Release|x64 {4C429783-0B01-449F-A36F-C2019233890B}.Debug|x64.ActiveCfg = Debug|x64 {4C429783-0B01-449F-A36F-C2019233890B}.Debug|x64.Build.0 = Debug|x64 {4C429783-0B01-449F-A36F-C2019233890B}.Release|x64.ActiveCfg = Release|x64 {4C429783-0B01-449F-A36F-C2019233890B}.Release|x64.Build.0 = Release|x64 {4C6E7F0A-7E6A-4713-B1D2-B7B4ADC992AF}.Debug|x64.ActiveCfg = Debug|x64 {4C6E7F0A-7E6A-4713-B1D2-B7B4ADC992AF}.Debug|x64.Build.0 = Debug|x64 {4C6E7F0A-7E6A-4713-B1D2-B7B4ADC992AF}.Release|x64.ActiveCfg = Release|x64 {4C6E7F0A-7E6A-4713-B1D2-B7B4ADC992AF}.Release|x64.Build.0 = Release|x64 {4E334022-7A71-4197-9E15-878F7EFC877E}.Debug|x64.ActiveCfg = Debug|x64 {4E334022-7A71-4197-9E15-878F7EFC877E}.Debug|x64.Build.0 = Debug|x64 {4E334022-7A71-4197-9E15-878F7EFC877E}.Release|x64.ActiveCfg = Release|x64 {4E334022-7A71-4197-9E15-878F7EFC877E}.Release|x64.Build.0 = Release|x64 {4ED1E400-CF16-48C2-B176-2BF186E73531}.Debug|x64.ActiveCfg = Debug|x64 {4ED1E400-CF16-48C2-B176-2BF186E73531}.Debug|x64.Build.0 = Debug|x64 {4ED1E400-CF16-48C2-B176-2BF186E73531}.Release|x64.ActiveCfg = Release|x64 {4ED1E400-CF16-48C2-B176-2BF186E73531}.Release|x64.Build.0 = Release|x64 {4FB4FF90-4E92-4CFB-A01F-C73D6861CA03}.Debug|x64.ActiveCfg = Debug|x64 {4FB4FF90-4E92-4CFB-A01F-C73D6861CA03}.Debug|x64.Build.0 = Debug|x64 {4FB4FF90-4E92-4CFB-A01F-C73D6861CA03}.Release|x64.ActiveCfg = Release|x64 {4FB4FF90-4E92-4CFB-A01F-C73D6861CA03}.Release|x64.Build.0 = Release|x64 {50FD1E47-2131-48D2-9435-5CB28DF6B15A}.Debug|x64.ActiveCfg = Debug|x64 {50FD1E47-2131-48D2-9435-5CB28DF6B15A}.Debug|x64.Build.0 = Debug|x64 {50FD1E47-2131-48D2-9435-5CB28DF6B15A}.Release|x64.ActiveCfg = Release|x64 {50FD1E47-2131-48D2-9435-5CB28DF6B15A}.Release|x64.Build.0 = Release|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Debug|x64.ActiveCfg = Debug|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Debug|x64.Build.0 = Debug|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Release|x64.ActiveCfg = Release|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Release|x64.Build.0 = Release|x64 {537F759B-B617-48D9-A2F3-7FB769A8F9B7}.Debug|x64.ActiveCfg = Debug|x64 {537F759B-B617-48D9-A2F3-7FB769A8F9B7}.Debug|x64.Build.0 = Debug|x64 {537F759B-B617-48D9-A2F3-7FB769A8F9B7}.Release|x64.ActiveCfg = Release|x64 {537F759B-B617-48D9-A2F3-7FB769A8F9B7}.Release|x64.Build.0 = Release|x64 {54E6F8F5-418E-44BE-8DF2-5A60D9EE971B}.Debug|x64.ActiveCfg = Debug|x64 {54E6F8F5-418E-44BE-8DF2-5A60D9EE971B}.Debug|x64.Build.0 = Debug|x64 {54E6F8F5-418E-44BE-8DF2-5A60D9EE971B}.Release|x64.ActiveCfg = Release|x64 {54E6F8F5-418E-44BE-8DF2-5A60D9EE971B}.Release|x64.Build.0 = Release|x64 {5580D11C-FDA6-4CF2-A0E8-1C2D3FBC11F1}.Debug|x64.ActiveCfg = Debug|x64 {5580D11C-FDA6-4CF2-A0E8-1C2D3FBC11F1}.Debug|x64.Build.0 = Debug|x64 {5580D11C-FDA6-4CF2-A0E8-1C2D3FBC11F1}.Release|x64.ActiveCfg = Release|x64 {5580D11C-FDA6-4CF2-A0E8-1C2D3FBC11F1}.Release|x64.Build.0 = Release|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Debug|x64.ActiveCfg = Debug|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Debug|x64.Build.0 = Debug|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Release|x64.ActiveCfg = Release|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Release|x64.Build.0 = Release|x64 {58386481-30B7-40FC-96AF-0723A4A7B228}.Debug|x64.ActiveCfg = Debug|x64 {58386481-30B7-40FC-96AF-0723A4A7B228}.Debug|x64.Build.0 = Debug|x64 {58386481-30B7-40FC-96AF-0723A4A7B228}.Release|x64.ActiveCfg = Release|x64 {58386481-30B7-40FC-96AF-0723A4A7B228}.Release|x64.Build.0 = Release|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Debug|x64.ActiveCfg = Debug|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Debug|x64.Build.0 = Debug|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Release|x64.ActiveCfg = Release|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Release|x64.Build.0 = Release|x64 {5A391A14-8E29-4788-93FC-EDADED31D32F}.Debug|x64.ActiveCfg = Debug|x64 {5A391A14-8E29-4788-93FC-EDADED31D32F}.Debug|x64.Build.0 = Debug|x64 {5A391A14-8E29-4788-93FC-EDADED31D32F}.Release|x64.ActiveCfg = Release|x64 {5A391A14-8E29-4788-93FC-EDADED31D32F}.Release|x64.Build.0 = Release|x64 {5AD07646-5E16-4CEF-B80A-BE5EE4D54FEF}.Debug|x64.ActiveCfg = Debug|x64 {5AD07646-5E16-4CEF-B80A-BE5EE4D54FEF}.Debug|x64.Build.0 = Debug|x64 {5AD07646-5E16-4CEF-B80A-BE5EE4D54FEF}.Release|x64.ActiveCfg = Release|x64 {5AD07646-5E16-4CEF-B80A-BE5EE4D54FEF}.Release|x64.Build.0 = Release|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Debug|x64.ActiveCfg = Debug|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Debug|x64.Build.0 = Debug|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Release|x64.ActiveCfg = Release|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Release|x64.Build.0 = Release|x64 {5D362DB7-D2BD-4907-AAD8-4B8627E72282}.Debug|x64.ActiveCfg = Debug|x64 {5D362DB7-D2BD-4907-AAD8-4B8627E72282}.Debug|x64.Build.0 = Debug|x64 {5D362DB7-D2BD-4907-AAD8-4B8627E72282}.Release|x64.ActiveCfg = Release|x64 {5D362DB7-D2BD-4907-AAD8-4B8627E72282}.Release|x64.Build.0 = Release|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Debug|x64.ActiveCfg = Debug|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Debug|x64.Build.0 = Debug|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Release|x64.ActiveCfg = Release|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Release|x64.Build.0 = Release|x64 {5F2B687A-1B42-439C-AEEC-135DD22FB851}.Debug|x64.ActiveCfg = Debug|x64 {5F2B687A-1B42-439C-AEEC-135DD22FB851}.Debug|x64.Build.0 = Debug|x64 {5F2B687A-1B42-439C-AEEC-135DD22FB851}.Release|x64.ActiveCfg = Release|x64 {5F2B687A-1B42-439C-AEEC-135DD22FB851}.Release|x64.Build.0 = Release|x64 {5F8A56F8-2C5B-48B6-9654-DD642D3E5F5C}.Debug|x64.ActiveCfg = Debug|x64 {5F8A56F8-2C5B-48B6-9654-DD642D3E5F5C}.Debug|x64.Build.0 = Debug|x64 {5F8A56F8-2C5B-48B6-9654-DD642D3E5F5C}.Release|x64.ActiveCfg = Release|x64 {5F8A56F8-2C5B-48B6-9654-DD642D3E5F5C}.Release|x64.Build.0 = Release|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Debug|x64.ActiveCfg = Debug|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Debug|x64.Build.0 = Debug|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Release|x64.ActiveCfg = Release|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Release|x64.Build.0 = Release|x64 {6068773F-FDA7-484F-8650-EE1AA5C3CB37}.Debug|x64.ActiveCfg = Debug|x64 {6068773F-FDA7-484F-8650-EE1AA5C3CB37}.Debug|x64.Build.0 = Debug|x64 {6068773F-FDA7-484F-8650-EE1AA5C3CB37}.Release|x64.ActiveCfg = Release|x64 {6068773F-FDA7-484F-8650-EE1AA5C3CB37}.Release|x64.Build.0 = Release|x64 {60B463D4-8CD5-4BF6-A25B-01BE13B87590}.Debug|x64.ActiveCfg = Debug|x64 {60B463D4-8CD5-4BF6-A25B-01BE13B87590}.Debug|x64.Build.0 = Debug|x64 {60B463D4-8CD5-4BF6-A25B-01BE13B87590}.Release|x64.ActiveCfg = Release|x64 {60B463D4-8CD5-4BF6-A25B-01BE13B87590}.Release|x64.Build.0 = Release|x64 {628FADA9-7047-4DD9-BD17-9FE4B5A1ADB0}.Debug|x64.ActiveCfg = Debug|x64 {628FADA9-7047-4DD9-BD17-9FE4B5A1ADB0}.Debug|x64.Build.0 = Debug|x64 {628FADA9-7047-4DD9-BD17-9FE4B5A1ADB0}.Release|x64.ActiveCfg = Release|x64 {628FADA9-7047-4DD9-BD17-9FE4B5A1ADB0}.Release|x64.Build.0 = Release|x64 {63B8184D-85E0-4E6A-9729-558C567D1D1D}.Debug|x64.ActiveCfg = Debug|x64 {63B8184D-85E0-4E6A-9729-558C567D1D1D}.Debug|x64.Build.0 = Debug|x64 {63B8184D-85E0-4E6A-9729-558C567D1D1D}.Release|x64.ActiveCfg = Release|x64 {63B8184D-85E0-4E6A-9729-558C567D1D1D}.Release|x64.Build.0 = Release|x64 {643B82A1-D009-46A9-92A0-2883399B05C2}.Debug|x64.ActiveCfg = Debug|x64 {643B82A1-D009-46A9-92A0-2883399B05C2}.Debug|x64.Build.0 = Debug|x64 {643B82A1-D009-46A9-92A0-2883399B05C2}.Release|x64.ActiveCfg = Release|x64 {643B82A1-D009-46A9-92A0-2883399B05C2}.Release|x64.Build.0 = Release|x64 {6516D6CF-8000-4341-9487-312BC83EE370}.Debug|x64.ActiveCfg = Debug|x64 {6516D6CF-8000-4341-9487-312BC83EE370}.Debug|x64.Build.0 = Debug|x64 {6516D6CF-8000-4341-9487-312BC83EE370}.Release|x64.ActiveCfg = Release|x64 {6516D6CF-8000-4341-9487-312BC83EE370}.Release|x64.Build.0 = Release|x64 {65D92D98-97E1-48F7-AEF6-75221CF48EA4}.Debug|x64.ActiveCfg = Debug|x64 {65D92D98-97E1-48F7-AEF6-75221CF48EA4}.Debug|x64.Build.0 = Debug|x64 {65D92D98-97E1-48F7-AEF6-75221CF48EA4}.Release|x64.ActiveCfg = Release|x64 {65D92D98-97E1-48F7-AEF6-75221CF48EA4}.Release|x64.Build.0 = Release|x64 {673277EC-D26B-414D-92E3-84EE873316A8}.Debug|x64.ActiveCfg = Debug|x64 {673277EC-D26B-414D-92E3-84EE873316A8}.Debug|x64.Build.0 = Debug|x64 {673277EC-D26B-414D-92E3-84EE873316A8}.Release|x64.ActiveCfg = Release|x64 {673277EC-D26B-414D-92E3-84EE873316A8}.Release|x64.Build.0 = Release|x64 {67AC1343-98FD-4143-92C0-559C55F749F5}.Debug|x64.ActiveCfg = Debug|x64 {67AC1343-98FD-4143-92C0-559C55F749F5}.Debug|x64.Build.0 = Debug|x64 {67AC1343-98FD-4143-92C0-559C55F749F5}.Release|x64.ActiveCfg = Release|x64 {67AC1343-98FD-4143-92C0-559C55F749F5}.Release|x64.Build.0 = Release|x64 {6851356E-A5D9-46A6-8262-A7E208729F18}.Debug|x64.ActiveCfg = Debug|x64 {6851356E-A5D9-46A6-8262-A7E208729F18}.Debug|x64.Build.0 = Debug|x64 {6851356E-A5D9-46A6-8262-A7E208729F18}.Release|x64.ActiveCfg = Release|x64 {6851356E-A5D9-46A6-8262-A7E208729F18}.Release|x64.Build.0 = Release|x64 {6AE1B8BE-D46A-4E99-87A2-F160FB950DCA}.Debug|x64.ActiveCfg = Debug|x64 {6AE1B8BE-D46A-4E99-87A2-F160FB950DCA}.Debug|x64.Build.0 = Debug|x64 {6AE1B8BE-D46A-4E99-87A2-F160FB950DCA}.Release|x64.ActiveCfg = Release|x64 {6AE1B8BE-D46A-4E99-87A2-F160FB950DCA}.Release|x64.Build.0 = Release|x64 {6B492754-9F80-44B3-A2A7-1D98AF06F3B2}.Debug|x64.ActiveCfg = Debug|x64 {6B492754-9F80-44B3-A2A7-1D98AF06F3B2}.Debug|x64.Build.0 = Debug|x64 {6B492754-9F80-44B3-A2A7-1D98AF06F3B2}.Release|x64.ActiveCfg = Release|x64 {6B492754-9F80-44B3-A2A7-1D98AF06F3B2}.Release|x64.Build.0 = Release|x64 {6BCEF2A5-0CEC-4CC6-9CB0-D3FBF871A408}.Debug|x64.ActiveCfg = Debug|x64 {6BCEF2A5-0CEC-4CC6-9CB0-D3FBF871A408}.Debug|x64.Build.0 = Debug|x64 {6BCEF2A5-0CEC-4CC6-9CB0-D3FBF871A408}.Release|x64.ActiveCfg = Release|x64 {6BCEF2A5-0CEC-4CC6-9CB0-D3FBF871A408}.Release|x64.Build.0 = Release|x64 {6D7C1169-3246-465F-B630-ECFEF4F3179A}.Debug|x64.ActiveCfg = Debug|x64 {6D7C1169-3246-465F-B630-ECFEF4F3179A}.Debug|x64.Build.0 = Debug|x64 {6D7C1169-3246-465F-B630-ECFEF4F3179A}.Release|x64.ActiveCfg = Release|x64 {6D7C1169-3246-465F-B630-ECFEF4F3179A}.Release|x64.Build.0 = Release|x64 {6F06A19B-0921-4B71-A3A5-B350B5FFEADB}.Debug|x64.ActiveCfg = Debug|x64 {6F06A19B-0921-4B71-A3A5-B350B5FFEADB}.Debug|x64.Build.0 = Debug|x64 {6F06A19B-0921-4B71-A3A5-B350B5FFEADB}.Release|x64.ActiveCfg = Release|x64 {6F06A19B-0921-4B71-A3A5-B350B5FFEADB}.Release|x64.Build.0 = Release|x64 {6F4953DA-FDC3-46CF-BF24-3752CCF2E1CB}.Debug|x64.ActiveCfg = Debug|x64 {6F4953DA-FDC3-46CF-BF24-3752CCF2E1CB}.Debug|x64.Build.0 = Debug|x64 {6F4953DA-FDC3-46CF-BF24-3752CCF2E1CB}.Release|x64.ActiveCfg = Release|x64 {6F4953DA-FDC3-46CF-BF24-3752CCF2E1CB}.Release|x64.Build.0 = Release|x64 {70EE1D40-0C65-4985-8EFC-BD40EE3A89B2}.Debug|x64.ActiveCfg = Debug|x64 {70EE1D40-0C65-4985-8EFC-BD40EE3A89B2}.Debug|x64.Build.0 = Debug|x64 {70EE1D40-0C65-4985-8EFC-BD40EE3A89B2}.Release|x64.ActiveCfg = Release|x64 {70EE1D40-0C65-4985-8EFC-BD40EE3A89B2}.Release|x64.Build.0 = Release|x64 {715EADD7-0FFE-4F1F-94E7-49302968DF79}.Debug|x64.ActiveCfg = Debug|x64 {715EADD7-0FFE-4F1F-94E7-49302968DF79}.Debug|x64.Build.0 = Debug|x64 {715EADD7-0FFE-4F1F-94E7-49302968DF79}.Release|x64.ActiveCfg = Release|x64 {715EADD7-0FFE-4F1F-94E7-49302968DF79}.Release|x64.Build.0 = Release|x64 {718CA6FA-6446-4E43-83DF-BA4E85E5886B}.Debug|x64.ActiveCfg = Debug|x64 {718CA6FA-6446-4E43-83DF-BA4E85E5886B}.Debug|x64.Build.0 = Debug|x64 {718CA6FA-6446-4E43-83DF-BA4E85E5886B}.Release|x64.ActiveCfg = Release|x64 {718CA6FA-6446-4E43-83DF-BA4E85E5886B}.Release|x64.Build.0 = Release|x64 {71D182E0-345A-4375-B0FA-3536821B0EE3}.Debug|x64.ActiveCfg = Debug|x64 {71D182E0-345A-4375-B0FA-3536821B0EE3}.Debug|x64.Build.0 = Debug|x64 {71D182E0-345A-4375-B0FA-3536821B0EE3}.Release|x64.ActiveCfg = Release|x64 {71D182E0-345A-4375-B0FA-3536821B0EE3}.Release|x64.Build.0 = Release|x64 {72598DD9-3F44-4E6A-B0B7-C5AE3FF43B1F}.Debug|x64.ActiveCfg = Debug|x64 {72598DD9-3F44-4E6A-B0B7-C5AE3FF43B1F}.Debug|x64.Build.0 = Debug|x64 {72598DD9-3F44-4E6A-B0B7-C5AE3FF43B1F}.Release|x64.ActiveCfg = Release|x64 {72598DD9-3F44-4E6A-B0B7-C5AE3FF43B1F}.Release|x64.Build.0 = Release|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Debug|x64.ActiveCfg = Debug|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Debug|x64.Build.0 = Debug|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Release|x64.ActiveCfg = Release|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Release|x64.Build.0 = Release|x64 {729E3905-FF7D-49C5-9871-6D35D839183E}.Debug|x64.ActiveCfg = Debug|x64 {729E3905-FF7D-49C5-9871-6D35D839183E}.Debug|x64.Build.0 = Debug|x64 {729E3905-FF7D-49C5-9871-6D35D839183E}.Release|x64.ActiveCfg = Release|x64 {729E3905-FF7D-49C5-9871-6D35D839183E}.Release|x64.Build.0 = Release|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Debug|x64.ActiveCfg = Debug|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Debug|x64.Build.0 = Debug|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Release|x64.ActiveCfg = Release|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Release|x64.Build.0 = Release|x64 {73F35C28-811C-4D77-916E-386EB139C001}.Debug|x64.ActiveCfg = Debug|x64 {73F35C28-811C-4D77-916E-386EB139C001}.Debug|x64.Build.0 = Debug|x64 {73F35C28-811C-4D77-916E-386EB139C001}.Release|x64.ActiveCfg = Release|x64 {73F35C28-811C-4D77-916E-386EB139C001}.Release|x64.Build.0 = Release|x64 {74243B75-816C-4077-8DF0-98D2C78B0E5D}.Debug|x64.ActiveCfg = Debug|x64 {74243B75-816C-4077-8DF0-98D2C78B0E5D}.Debug|x64.Build.0 = Debug|x64 {74243B75-816C-4077-8DF0-98D2C78B0E5D}.Release|x64.ActiveCfg = Release|x64 {74243B75-816C-4077-8DF0-98D2C78B0E5D}.Release|x64.Build.0 = Release|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Debug|x64.ActiveCfg = Debug|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Debug|x64.Build.0 = Debug|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Release|x64.ActiveCfg = Release|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Release|x64.Build.0 = Release|x64 {779425B1-2211-499B-A7CC-4F9EC6CB0D25}.Debug|x64.ActiveCfg = Debug|x64 {779425B1-2211-499B-A7CC-4F9EC6CB0D25}.Debug|x64.Build.0 = Debug|x64 {779425B1-2211-499B-A7CC-4F9EC6CB0D25}.Release|x64.ActiveCfg = Release|x64 {779425B1-2211-499B-A7CC-4F9EC6CB0D25}.Release|x64.Build.0 = Release|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Debug|x64.ActiveCfg = Debug|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Debug|x64.Build.0 = Debug|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Release|x64.ActiveCfg = Release|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Release|x64.Build.0 = Release|x64 {7D71EE07-6CE2-49FA-8AB8-976800A050A0}.Debug|x64.ActiveCfg = Debug|x64 {7D71EE07-6CE2-49FA-8AB8-976800A050A0}.Debug|x64.Build.0 = Debug|x64 {7D71EE07-6CE2-49FA-8AB8-976800A050A0}.Release|x64.ActiveCfg = Release|x64 {7D71EE07-6CE2-49FA-8AB8-976800A050A0}.Release|x64.Build.0 = Release|x64 {7DC3B3DD-73ED-4602-9AF3-8D7053620DEA}.Debug|x64.ActiveCfg = Debug|x64 {7DC3B3DD-73ED-4602-9AF3-8D7053620DEA}.Debug|x64.Build.0 = Debug|x64 {7DC3B3DD-73ED-4602-9AF3-8D7053620DEA}.Release|x64.ActiveCfg = Release|x64 {7DC3B3DD-73ED-4602-9AF3-8D7053620DEA}.Release|x64.Build.0 = Release|x64 {7DFEB4A5-8B04-4302-9D09-8144918FCF81}.Debug|x64.ActiveCfg = Debug|x64 {7DFEB4A5-8B04-4302-9D09-8144918FCF81}.Debug|x64.Build.0 = Debug|x64 {7DFEB4A5-8B04-4302-9D09-8144918FCF81}.Release|x64.ActiveCfg = Release|x64 {7DFEB4A5-8B04-4302-9D09-8144918FCF81}.Release|x64.Build.0 = Release|x64 {7E0106F8-A597-48D5-B4F2-E0FC4D95EE95}.Debug|x64.ActiveCfg = Debug|x64 {7E0106F8-A597-48D5-B4F2-E0FC4D95EE95}.Debug|x64.Build.0 = Debug|x64 {7E0106F8-A597-48D5-B4F2-E0FC4D95EE95}.Release|x64.ActiveCfg = Release|x64 {7E0106F8-A597-48D5-B4F2-E0FC4D95EE95}.Release|x64.Build.0 = Release|x64 {7F51CD29-3BCD-4DD8-B327-F384B5A616D1}.Debug|x64.ActiveCfg = Debug|x64 {7F51CD29-3BCD-4DD8-B327-F384B5A616D1}.Debug|x64.Build.0 = Debug|x64 {7F51CD29-3BCD-4DD8-B327-F384B5A616D1}.Release|x64.ActiveCfg = Release|x64 {7F51CD29-3BCD-4DD8-B327-F384B5A616D1}.Release|x64.Build.0 = Release|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Debug|x64.ActiveCfg = Debug|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Debug|x64.Build.0 = Debug|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Release|x64.ActiveCfg = Release|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Release|x64.Build.0 = Release|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Debug|x64.ActiveCfg = Debug|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Debug|x64.Build.0 = Debug|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Release|x64.ActiveCfg = Release|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Release|x64.Build.0 = Release|x64 {80AF1B7D-B8CE-4AF0-AE3B-1DABED1B57E7}.Debug|x64.ActiveCfg = Debug|x64 {80AF1B7D-B8CE-4AF0-AE3B-1DABED1B57E7}.Debug|x64.Build.0 = Debug|x64 {80AF1B7D-B8CE-4AF0-AE3B-1DABED1B57E7}.Release|x64.ActiveCfg = Release|x64 {80AF1B7D-B8CE-4AF0-AE3B-1DABED1B57E7}.Release|x64.Build.0 = Release|x64 {8145F442-0EF6-4E55-BAED-8DDE72022355}.Debug|x64.ActiveCfg = Debug|x64 {8145F442-0EF6-4E55-BAED-8DDE72022355}.Debug|x64.Build.0 = Debug|x64 {8145F442-0EF6-4E55-BAED-8DDE72022355}.Release|x64.ActiveCfg = Release|x64 {8145F442-0EF6-4E55-BAED-8DDE72022355}.Release|x64.Build.0 = Release|x64 {85D4076B-896B-4EBB-8F3A-8B44C24CD452}.Debug|x64.ActiveCfg = Debug|x64 {85D4076B-896B-4EBB-8F3A-8B44C24CD452}.Debug|x64.Build.0 = Debug|x64 {85D4076B-896B-4EBB-8F3A-8B44C24CD452}.Release|x64.ActiveCfg = Release|x64 {85D4076B-896B-4EBB-8F3A-8B44C24CD452}.Release|x64.Build.0 = Release|x64 {85DBDA9B-AEF6-43E7-B8B5-05FF2BEC61A3}.Debug|x64.ActiveCfg = Debug|x64 {85DBDA9B-AEF6-43E7-B8B5-05FF2BEC61A3}.Debug|x64.Build.0 = Debug|x64 {85DBDA9B-AEF6-43E7-B8B5-05FF2BEC61A3}.Release|x64.ActiveCfg = Release|x64 {85DBDA9B-AEF6-43E7-B8B5-05FF2BEC61A3}.Release|x64.Build.0 = Release|x64 {86EE22CC-6D3C-4F81-ADC8-394946F0DA81}.Debug|x64.ActiveCfg = Debug|x64 {86EE22CC-6D3C-4F81-ADC8-394946F0DA81}.Debug|x64.Build.0 = Debug|x64 {86EE22CC-6D3C-4F81-ADC8-394946F0DA81}.Release|x64.ActiveCfg = Release|x64 {86EE22CC-6D3C-4F81-ADC8-394946F0DA81}.Release|x64.Build.0 = Release|x64 {88D239E4-EB7D-4E0A-BE3A-AD78B9F408FC}.Debug|x64.ActiveCfg = Debug|x64 {88D239E4-EB7D-4E0A-BE3A-AD78B9F408FC}.Debug|x64.Build.0 = Debug|x64 {88D239E4-EB7D-4E0A-BE3A-AD78B9F408FC}.Release|x64.ActiveCfg = Release|x64 {88D239E4-EB7D-4E0A-BE3A-AD78B9F408FC}.Release|x64.Build.0 = Release|x64 {89B6AF14-08A0-437A-B31D-A8A3492FA965}.Debug|x64.ActiveCfg = Debug|x64 {89B6AF14-08A0-437A-B31D-A8A3492FA965}.Debug|x64.Build.0 = Debug|x64 {89B6AF14-08A0-437A-B31D-A8A3492FA965}.Release|x64.ActiveCfg = Release|x64 {89B6AF14-08A0-437A-B31D-A8A3492FA965}.Release|x64.Build.0 = Release|x64 {89F947CA-DDEF-4131-8AFB-584ABA4A1302}.Debug|x64.ActiveCfg = Debug|x64 {89F947CA-DDEF-4131-8AFB-584ABA4A1302}.Debug|x64.Build.0 = Debug|x64 {89F947CA-DDEF-4131-8AFB-584ABA4A1302}.Release|x64.ActiveCfg = Release|x64 {89F947CA-DDEF-4131-8AFB-584ABA4A1302}.Release|x64.Build.0 = Release|x64 {8A0FA780-068A-4534-AA2F-4FF4CF977AF2}.Debug|x64.ActiveCfg = Debug|x64 {8A0FA780-068A-4534-AA2F-4FF4CF977AF2}.Debug|x64.Build.0 = Debug|x64 {8A0FA780-068A-4534-AA2F-4FF4CF977AF2}.Release|x64.ActiveCfg = Release|x64 {8A4872D7-A234-4B9B-8215-82C6BB15F3A2}.Debug|x64.ActiveCfg = Debug|x64 {8A4872D7-A234-4B9B-8215-82C6BB15F3A2}.Debug|x64.Build.0 = Debug|x64 {8A4872D7-A234-4B9B-8215-82C6BB15F3A2}.Release|x64.ActiveCfg = Release|x64 {8A4872D7-A234-4B9B-8215-82C6BB15F3A2}.Release|x64.Build.0 = Release|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Debug|x64.ActiveCfg = Debug|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Debug|x64.Build.0 = Debug|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Release|x64.ActiveCfg = Release|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Release|x64.Build.0 = Release|x64 {8C6D73E0-0A6F-4487-A040-0EC78D7D6D9A}.Debug|x64.ActiveCfg = Debug|x64 {8C6D73E0-0A6F-4487-A040-0EC78D7D6D9A}.Debug|x64.Build.0 = Debug|x64 {8C6D73E0-0A6F-4487-A040-0EC78D7D6D9A}.Release|x64.ActiveCfg = Release|x64 {8C6D73E0-0A6F-4487-A040-0EC78D7D6D9A}.Release|x64.Build.0 = Release|x64 {8CD79300-941F-4FDD-A371-92BF0EFBA0FC}.Debug|x64.ActiveCfg = Debug|x64 {8CD79300-941F-4FDD-A371-92BF0EFBA0FC}.Debug|x64.Build.0 = Debug|x64 {8CD79300-941F-4FDD-A371-92BF0EFBA0FC}.Release|x64.ActiveCfg = Release|x64 {8CD79300-941F-4FDD-A371-92BF0EFBA0FC}.Release|x64.Build.0 = Release|x64 {8D6BB292-9E1C-413D-9F98-4864BDC1514A}.Debug|x64.ActiveCfg = Debug|x64 {8D6BB292-9E1C-413D-9F98-4864BDC1514A}.Debug|x64.Build.0 = Debug|x64 {8D6BB292-9E1C-413D-9F98-4864BDC1514A}.Release|x64.ActiveCfg = Release|x64 {8D6BB292-9E1C-413D-9F98-4864BDC1514A}.Release|x64.Build.0 = Release|x64 {8D75FA1A-EC74-4F88-8AC1-CE3F98E4D828}.Debug|x64.ActiveCfg = Debug|x64 {8D75FA1A-EC74-4F88-8AC1-CE3F98E4D828}.Debug|x64.Build.0 = Debug|x64 {8D75FA1A-EC74-4F88-8AC1-CE3F98E4D828}.Release|x64.ActiveCfg = Release|x64 {8D75FA1A-EC74-4F88-8AC1-CE3F98E4D828}.Release|x64.Build.0 = Release|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Debug|x64.ActiveCfg = Debug|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Debug|x64.Build.0 = Debug|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Release|x64.ActiveCfg = Release|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Release|x64.Build.0 = Release|x64 {8E374371-30E1-4623-8755-2A2F3742170B}.Debug|x64.ActiveCfg = Debug|x64 {8E374371-30E1-4623-8755-2A2F3742170B}.Debug|x64.Build.0 = Debug|x64 {8E374371-30E1-4623-8755-2A2F3742170B}.Release|x64.ActiveCfg = Release|x64 {8E374371-30E1-4623-8755-2A2F3742170B}.Release|x64.Build.0 = Release|x64 {8F42055F-FFD9-4B10-B266-6DD32923F0AC}.Debug|x64.ActiveCfg = Debug|x64 {8F42055F-FFD9-4B10-B266-6DD32923F0AC}.Debug|x64.Build.0 = Debug|x64 {8F42055F-FFD9-4B10-B266-6DD32923F0AC}.Release|x64.ActiveCfg = Release|x64 {8F42055F-FFD9-4B10-B266-6DD32923F0AC}.Release|x64.Build.0 = Release|x64 {901F04DB-E1A5-4A41-8B81-9D31C19ACD59}.Debug|x64.ActiveCfg = Debug|x64 {901F04DB-E1A5-4A41-8B81-9D31C19ACD59}.Debug|x64.Build.0 = Debug|x64 {901F04DB-E1A5-4A41-8B81-9D31C19ACD59}.Release|x64.ActiveCfg = Release|x64 {901F04DB-E1A5-4A41-8B81-9D31C19ACD59}.Release|x64.Build.0 = Release|x64 {90C5FCF1-8243-4988-A4EA-AA6A88268373}.Debug|x64.ActiveCfg = Debug|x64 {90C5FCF1-8243-4988-A4EA-AA6A88268373}.Debug|x64.Build.0 = Debug|x64 {90C5FCF1-8243-4988-A4EA-AA6A88268373}.Release|x64.ActiveCfg = Release|x64 {90C5FCF1-8243-4988-A4EA-AA6A88268373}.Release|x64.Build.0 = Release|x64 {91365DAC-BF62-4B96-919D-7C474D029B61}.Debug|x64.ActiveCfg = Debug|x64 {91365DAC-BF62-4B96-919D-7C474D029B61}.Debug|x64.Build.0 = Debug|x64 {91365DAC-BF62-4B96-919D-7C474D029B61}.Release|x64.ActiveCfg = Release|x64 {91365DAC-BF62-4B96-919D-7C474D029B61}.Release|x64.Build.0 = Release|x64 {9186EAC4-2F34-4F17-B940-6585D7869BCD}.Debug|x64.ActiveCfg = Debug|x64 {9186EAC4-2F34-4F17-B940-6585D7869BCD}.Debug|x64.Build.0 = Debug|x64 {9186EAC4-2F34-4F17-B940-6585D7869BCD}.Release|x64.ActiveCfg = Release|x64 {9186EAC4-2F34-4F17-B940-6585D7869BCD}.Release|x64.Build.0 = Release|x64 {91E19AEB-7B75-43E0-B8B4-D2BB60D839EA}.Debug|x64.ActiveCfg = Debug|x64 {91E19AEB-7B75-43E0-B8B4-D2BB60D839EA}.Debug|x64.Build.0 = Debug|x64 {91E19AEB-7B75-43E0-B8B4-D2BB60D839EA}.Release|x64.ActiveCfg = Release|x64 {91E19AEB-7B75-43E0-B8B4-D2BB60D839EA}.Release|x64.Build.0 = Release|x64 {92388A20-50FC-45F8-89E3-71F1618EFABB}.Debug|x64.ActiveCfg = Debug|x64 {92388A20-50FC-45F8-89E3-71F1618EFABB}.Debug|x64.Build.0 = Debug|x64 {92388A20-50FC-45F8-89E3-71F1618EFABB}.Release|x64.ActiveCfg = Release|x64 {92388A20-50FC-45F8-89E3-71F1618EFABB}.Release|x64.Build.0 = Release|x64 {924B2937-0B53-4DC6-B7E1-5F3102728F89}.Debug|x64.ActiveCfg = Debug|x64 {924B2937-0B53-4DC6-B7E1-5F3102728F89}.Debug|x64.Build.0 = Debug|x64 {924B2937-0B53-4DC6-B7E1-5F3102728F89}.Release|x64.ActiveCfg = Release|x64 {924B2937-0B53-4DC6-B7E1-5F3102728F89}.Release|x64.Build.0 = Release|x64 {940C5974-9EF3-4FAC-9820-976B0711F69B}.Debug|x64.ActiveCfg = Debug|x64 {940C5974-9EF3-4FAC-9820-976B0711F69B}.Debug|x64.Build.0 = Debug|x64 {940C5974-9EF3-4FAC-9820-976B0711F69B}.Release|x64.ActiveCfg = Release|x64 {940C5974-9EF3-4FAC-9820-976B0711F69B}.Release|x64.Build.0 = Release|x64 {95B683BD-B9DC-400F-9BC0-8F1505F08BF5}.Debug|x64.ActiveCfg = Debug|x64 {95B683BD-B9DC-400F-9BC0-8F1505F08BF5}.Debug|x64.Build.0 = Debug|x64 {95B683BD-B9DC-400F-9BC0-8F1505F08BF5}.Release|x64.ActiveCfg = Release|x64 {95B683BD-B9DC-400F-9BC0-8F1505F08BF5}.Release|x64.Build.0 = Release|x64 {96D00A19-5CEF-4CC5-BDE8-E33C68BCE90F}.Debug|x64.ActiveCfg = Debug|x64 {96D00A19-5CEF-4CC5-BDE8-E33C68BCE90F}.Debug|x64.Build.0 = Debug|x64 {96D00A19-5CEF-4CC5-BDE8-E33C68BCE90F}.Release|x64.ActiveCfg = Release|x64 {96D00A19-5CEF-4CC5-BDE8-E33C68BCE90F}.Release|x64.Build.0 = Release|x64 {98ACBE5D-1A92-46F9-AA81-533412172952}.Debug|x64.ActiveCfg = Debug|x64 {98ACBE5D-1A92-46F9-AA81-533412172952}.Debug|x64.Build.0 = Debug|x64 {98ACBE5D-1A92-46F9-AA81-533412172952}.Release|x64.ActiveCfg = Release|x64 {98ACBE5D-1A92-46F9-AA81-533412172952}.Release|x64.Build.0 = Release|x64 {9935E8A1-F3F9-41D4-BD81-AD3FD04642E9}.Debug|x64.ActiveCfg = Debug|x64 {9935E8A1-F3F9-41D4-BD81-AD3FD04642E9}.Debug|x64.Build.0 = Debug|x64 {9935E8A1-F3F9-41D4-BD81-AD3FD04642E9}.Release|x64.ActiveCfg = Release|x64 {9935E8A1-F3F9-41D4-BD81-AD3FD04642E9}.Release|x64.Build.0 = Release|x64 {99F7F00F-1DE5-45EA-992B-64BA282FAC76}.Debug|x64.ActiveCfg = Debug|x64 {99F7F00F-1DE5-45EA-992B-64BA282FAC76}.Debug|x64.Build.0 = Debug|x64 {99F7F00F-1DE5-45EA-992B-64BA282FAC76}.Release|x64.ActiveCfg = Release|x64 {99F7F00F-1DE5-45EA-992B-64BA282FAC76}.Release|x64.Build.0 = Release|x64 {9A4078F8-B8E4-4EC6-A6FF-4F29DAD9CE48}.Debug|x64.ActiveCfg = Debug|x64 {9A4078F8-B8E4-4EC6-A6FF-4F29DAD9CE48}.Debug|x64.Build.0 = Debug|x64 {9A4078F8-B8E4-4EC6-A6FF-4F29DAD9CE48}.Release|x64.ActiveCfg = Release|x64 {9A4078F8-B8E4-4EC6-A6FF-4F29DAD9CE48}.Release|x64.Build.0 = Release|x64 {9AE2DAF9-10C4-4EC3-AE52-AD5EE9C77C55}.Debug|x64.ActiveCfg = Debug|x64 {9AE2DAF9-10C4-4EC3-AE52-AD5EE9C77C55}.Debug|x64.Build.0 = Debug|x64 {9AE2DAF9-10C4-4EC3-AE52-AD5EE9C77C55}.Release|x64.ActiveCfg = Release|x64 {9AE2DAF9-10C4-4EC3-AE52-AD5EE9C77C55}.Release|x64.Build.0 = Release|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Debug|x64.ActiveCfg = Debug|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Debug|x64.Build.0 = Debug|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Release|x64.ActiveCfg = Release|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Release|x64.Build.0 = Release|x64 {9D9E33EB-4C24-4646-A3FB-35DA17247917}.Debug|x64.ActiveCfg = Debug|x64 {9D9E33EB-4C24-4646-A3FB-35DA17247917}.Debug|x64.Build.0 = Debug|x64 {9D9E33EB-4C24-4646-A3FB-35DA17247917}.Release|x64.ActiveCfg = Release|x64 {9D9E33EB-4C24-4646-A3FB-35DA17247917}.Release|x64.Build.0 = Release|x64 {9E9E3D25-2139-4A5D-9200-18148DDEAD45}.Debug|x64.ActiveCfg = Debug|x64 {9E9E3D25-2139-4A5D-9200-18148DDEAD45}.Debug|x64.Build.0 = Debug|x64 {9E9E3D25-2139-4A5D-9200-18148DDEAD45}.Release|x64.ActiveCfg = Release|x64 {9E9E3D25-2139-4A5D-9200-18148DDEAD45}.Release|x64.Build.0 = Release|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Debug|x64.ActiveCfg = Debug|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Debug|x64.Build.0 = Debug|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Release|x64.ActiveCfg = Release|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Release|x64.Build.0 = Release|x64 {9FF62356-30B4-42A1-8DC7-45262A18DD44}.Debug|x64.ActiveCfg = Debug|x64 {9FF62356-30B4-42A1-8DC7-45262A18DD44}.Debug|x64.Build.0 = Debug|x64 {9FF62356-30B4-42A1-8DC7-45262A18DD44}.Release|x64.ActiveCfg = Release|x64 {9FF62356-30B4-42A1-8DC7-45262A18DD44}.Release|x64.Build.0 = Release|x64 {A216BF23-FC5C-4426-BF20-8568A2AA5FA0}.Debug|x64.ActiveCfg = Debug|x64 {A216BF23-FC5C-4426-BF20-8568A2AA5FA0}.Debug|x64.Build.0 = Debug|x64 {A216BF23-FC5C-4426-BF20-8568A2AA5FA0}.Release|x64.ActiveCfg = Release|x64 {A216BF23-FC5C-4426-BF20-8568A2AA5FA0}.Release|x64.Build.0 = Release|x64 {A2A0FAEA-2B7C-4FC3-B904-1DB4DEACF88D}.Debug|x64.ActiveCfg = Debug|x64 {A2A0FAEA-2B7C-4FC3-B904-1DB4DEACF88D}.Debug|x64.Build.0 = Debug|x64 {A2A0FAEA-2B7C-4FC3-B904-1DB4DEACF88D}.Release|x64.ActiveCfg = Release|x64 {A2A0FAEA-2B7C-4FC3-B904-1DB4DEACF88D}.Release|x64.Build.0 = Release|x64 {A2DEA0DC-04F3-4384-BCC2-F7EE2CFD6EE7}.Debug|x64.ActiveCfg = Debug|x64 {A2DEA0DC-04F3-4384-BCC2-F7EE2CFD6EE7}.Debug|x64.Build.0 = Debug|x64 {A2DEA0DC-04F3-4384-BCC2-F7EE2CFD6EE7}.Release|x64.ActiveCfg = Release|x64 {A2DEA0DC-04F3-4384-BCC2-F7EE2CFD6EE7}.Release|x64.Build.0 = Release|x64 {A38EFCDB-53D6-4474-97F3-0DDC6CE70D76}.Debug|x64.ActiveCfg = Debug|x64 {A38EFCDB-53D6-4474-97F3-0DDC6CE70D76}.Debug|x64.Build.0 = Debug|x64 {A38EFCDB-53D6-4474-97F3-0DDC6CE70D76}.Release|x64.ActiveCfg = Release|x64 {A38EFCDB-53D6-4474-97F3-0DDC6CE70D76}.Release|x64.Build.0 = Release|x64 {A5794EFF-8232-4E2B-B52C-908823048F54}.Debug|x64.ActiveCfg = Debug|x64 {A5794EFF-8232-4E2B-B52C-908823048F54}.Debug|x64.Build.0 = Debug|x64 {A5794EFF-8232-4E2B-B52C-908823048F54}.Release|x64.ActiveCfg = Release|x64 {A5794EFF-8232-4E2B-B52C-908823048F54}.Release|x64.Build.0 = Release|x64 {A57D9365-172E-4782-ADC6-82A594E30943}.Debug|x64.ActiveCfg = Debug|x64 {A57D9365-172E-4782-ADC6-82A594E30943}.Debug|x64.Build.0 = Debug|x64 {A57D9365-172E-4782-ADC6-82A594E30943}.Release|x64.ActiveCfg = Release|x64 {A57D9365-172E-4782-ADC6-82A594E30943}.Release|x64.Build.0 = Release|x64 {A5DF0746-5496-4C29-9CCD-5FA76604BF8B}.Debug|x64.ActiveCfg = Debug|x64 {A5DF0746-5496-4C29-9CCD-5FA76604BF8B}.Debug|x64.Build.0 = Debug|x64 {A5DF0746-5496-4C29-9CCD-5FA76604BF8B}.Release|x64.ActiveCfg = Release|x64 {A5DF0746-5496-4C29-9CCD-5FA76604BF8B}.Release|x64.Build.0 = Release|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Debug|x64.ActiveCfg = Debug|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Debug|x64.Build.0 = Debug|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Release|x64.ActiveCfg = Release|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Release|x64.Build.0 = Release|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Debug|x64.ActiveCfg = Debug|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Debug|x64.Build.0 = Debug|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Release|x64.ActiveCfg = Release|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Release|x64.Build.0 = Release|x64 {A911D62B-9D48-4807-B183-7127F1AC7A83}.Debug|x64.ActiveCfg = Debug|x64 {A911D62B-9D48-4807-B183-7127F1AC7A83}.Debug|x64.Build.0 = Debug|x64 {A911D62B-9D48-4807-B183-7127F1AC7A83}.Release|x64.ActiveCfg = Release|x64 {A911D62B-9D48-4807-B183-7127F1AC7A83}.Release|x64.Build.0 = Release|x64 {AB15A115-E429-4123-BEBF-206FBA4CF615}.Debug|x64.ActiveCfg = Debug|x64 {AB15A115-E429-4123-BEBF-206FBA4CF615}.Debug|x64.Build.0 = Debug|x64 {AB15A115-E429-4123-BEBF-206FBA4CF615}.Release|x64.ActiveCfg = Release|x64 {AB15A115-E429-4123-BEBF-206FBA4CF615}.Release|x64.Build.0 = Release|x64 {ABD4B53D-94CD-4C6A-B30A-CB6FEBA16296}.Debug|x64.ActiveCfg = Debug|x64 {ABD4B53D-94CD-4C6A-B30A-CB6FEBA16296}.Debug|x64.Build.0 = Debug|x64 {ABD4B53D-94CD-4C6A-B30A-CB6FEBA16296}.Release|x64.ActiveCfg = Release|x64 {ABD4B53D-94CD-4C6A-B30A-CB6FEBA16296}.Release|x64.Build.0 = Release|x64 {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Debug|x64.ActiveCfg = Debug|x64 {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Debug|x64.Build.0 = Debug|x64 {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Release|x64.ActiveCfg = Release|x64 {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Release|x64.Build.0 = Release|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Debug|x64.ActiveCfg = Debug|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Debug|x64.Build.0 = Debug|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Release|x64.ActiveCfg = Release|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Release|x64.Build.0 = Release|x64 {AEAA72CD-E060-417C-9CA1-49B4738384E0}.Debug|x64.ActiveCfg = Debug|x64 {AEAA72CD-E060-417C-9CA1-49B4738384E0}.Debug|x64.Build.0 = Debug|x64 {AEAA72CD-E060-417C-9CA1-49B4738384E0}.Release|x64.ActiveCfg = Release|x64 {AEAA72CD-E060-417C-9CA1-49B4738384E0}.Release|x64.Build.0 = Release|x64 {AF0B7480-EBE3-486B-B0C8-134910BC9324}.Debug|x64.ActiveCfg = Debug|x64 {AF0B7480-EBE3-486B-B0C8-134910BC9324}.Debug|x64.Build.0 = Debug|x64 {AF0B7480-EBE3-486B-B0C8-134910BC9324}.Release|x64.ActiveCfg = Release|x64 {AF0B7480-EBE3-486B-B0C8-134910BC9324}.Release|x64.Build.0 = Release|x64 {B2DC2F89-0724-4110-8934-D1173BD73D44}.Debug|x64.ActiveCfg = Debug|x64 {B2DC2F89-0724-4110-8934-D1173BD73D44}.Debug|x64.Build.0 = Debug|x64 {B2DC2F89-0724-4110-8934-D1173BD73D44}.Release|x64.ActiveCfg = Release|x64 {B2DC2F89-0724-4110-8934-D1173BD73D44}.Release|x64.Build.0 = Release|x64 {B30C6212-A160-405A-8FE7-340E721738A2}.Debug|x64.ActiveCfg = Debug|x64 {B30C6212-A160-405A-8FE7-340E721738A2}.Debug|x64.Build.0 = Debug|x64 {B30C6212-A160-405A-8FE7-340E721738A2}.Release|x64.ActiveCfg = Release|x64 {B30C6212-A160-405A-8FE7-340E721738A2}.Release|x64.Build.0 = Release|x64 {B35BFA09-DE68-483B-AB61-8790E8F060A8}.Debug|x64.ActiveCfg = Debug|x64 {B35BFA09-DE68-483B-AB61-8790E8F060A8}.Debug|x64.Build.0 = Debug|x64 {B35BFA09-DE68-483B-AB61-8790E8F060A8}.Release|x64.ActiveCfg = Release|x64 {B35BFA09-DE68-483B-AB61-8790E8F060A8}.Release|x64.Build.0 = Release|x64 {B36EE2A8-1487-47BB-B3B9-ABCB732B35F3}.Debug|x64.ActiveCfg = Debug|x64 {B36EE2A8-1487-47BB-B3B9-ABCB732B35F3}.Debug|x64.Build.0 = Debug|x64 {B36EE2A8-1487-47BB-B3B9-ABCB732B35F3}.Release|x64.ActiveCfg = Release|x64 {B36EE2A8-1487-47BB-B3B9-ABCB732B35F3}.Release|x64.Build.0 = Release|x64 {B36F115C-8139-4C35-A3E7-E6BF9F3DA793}.Debug|x64.ActiveCfg = Debug|x64 {B36F115C-8139-4C35-A3E7-E6BF9F3DA793}.Debug|x64.Build.0 = Debug|x64 {B36F115C-8139-4C35-A3E7-E6BF9F3DA793}.Release|x64.ActiveCfg = Release|x64 {B36F115C-8139-4C35-A3E7-E6BF9F3DA793}.Release|x64.Build.0 = Release|x64 {B379539C-E130-460D-AE82-4EBDD1A97845}.Debug|x64.ActiveCfg = Debug|x64 {B379539C-E130-460D-AE82-4EBDD1A97845}.Debug|x64.Build.0 = Debug|x64 {B379539C-E130-460D-AE82-4EBDD1A97845}.Release|x64.ActiveCfg = Release|x64 {B379539C-E130-460D-AE82-4EBDD1A97845}.Release|x64.Build.0 = Release|x64 {B440BB05-37A8-42EA-98D3-D83EB113E497}.Debug|x64.ActiveCfg = Debug|x64 {B440BB05-37A8-42EA-98D3-D83EB113E497}.Debug|x64.Build.0 = Debug|x64 {B440BB05-37A8-42EA-98D3-D83EB113E497}.Release|x64.ActiveCfg = Release|x64 {B440BB05-37A8-42EA-98D3-D83EB113E497}.Release|x64.Build.0 = Release|x64 {B6DA6617-D98F-4A4D-A7C4-A317212924BF}.Debug|x64.ActiveCfg = Debug|x64 {B6DA6617-D98F-4A4D-A7C4-A317212924BF}.Debug|x64.Build.0 = Debug|x64 {B6DA6617-D98F-4A4D-A7C4-A317212924BF}.Release|x64.ActiveCfg = Release|x64 {B6DA6617-D98F-4A4D-A7C4-A317212924BF}.Release|x64.Build.0 = Release|x64 {B6F4B85D-FE55-4A1B-AE97-D4A9ECFE195F}.Debug|x64.ActiveCfg = Debug|x64 {B6F4B85D-FE55-4A1B-AE97-D4A9ECFE195F}.Debug|x64.Build.0 = Debug|x64 {B6F4B85D-FE55-4A1B-AE97-D4A9ECFE195F}.Release|x64.ActiveCfg = Release|x64 {B6F4B85D-FE55-4A1B-AE97-D4A9ECFE195F}.Release|x64.Build.0 = Release|x64 {B775480C-5B32-4F64-B026-47367280EC56}.Debug|x64.ActiveCfg = Debug|x64 {B775480C-5B32-4F64-B026-47367280EC56}.Debug|x64.Build.0 = Debug|x64 {B775480C-5B32-4F64-B026-47367280EC56}.Release|x64.ActiveCfg = Release|x64 {B775480C-5B32-4F64-B026-47367280EC56}.Release|x64.Build.0 = Release|x64 {B887EA26-846C-4D6A-B0E4-432487506BC7}.Debug|x64.ActiveCfg = Debug|x64 {B887EA26-846C-4D6A-B0E4-432487506BC7}.Debug|x64.Build.0 = Debug|x64 {B887EA26-846C-4D6A-B0E4-432487506BC7}.Release|x64.ActiveCfg = Release|x64 {B887EA26-846C-4D6A-B0E4-432487506BC7}.Release|x64.Build.0 = Release|x64 {BABC6427-E533-4DCF-91E3-B5B2ED253F46}.Debug|x64.ActiveCfg = Debug|x64 {BABC6427-E533-4DCF-91E3-B5B2ED253F46}.Debug|x64.Build.0 = Debug|x64 {BABC6427-E533-4DCF-91E3-B5B2ED253F46}.Release|x64.ActiveCfg = Release|x64 {BABC6427-E533-4DCF-91E3-B5B2ED253F46}.Release|x64.Build.0 = Release|x64 {BAE107BA-7618-4972-8188-2D3CDAAE0453}.Debug|x64.ActiveCfg = Debug|x64 {BAE107BA-7618-4972-8188-2D3CDAAE0453}.Debug|x64.Build.0 = Debug|x64 {BAE107BA-7618-4972-8188-2D3CDAAE0453}.Release|x64.ActiveCfg = Release|x64 {BAE107BA-7618-4972-8188-2D3CDAAE0453}.Release|x64.Build.0 = Release|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Debug|x64.ActiveCfg = Debug|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Debug|x64.Build.0 = Debug|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Release|x64.ActiveCfg = Release|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Release|x64.Build.0 = Release|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Debug|x64.ActiveCfg = Debug|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Debug|x64.Build.0 = Debug|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Release|x64.ActiveCfg = Release|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Release|x64.Build.0 = Release|x64 {BF3B6C3A-3073-4AD4-BB41-A41047231982}.Debug|x64.ActiveCfg = Debug|x64 {BF3B6C3A-3073-4AD4-BB41-A41047231982}.Debug|x64.Build.0 = Debug|x64 {BF3B6C3A-3073-4AD4-BB41-A41047231982}.Release|x64.ActiveCfg = Release|x64 {BF3B6C3A-3073-4AD4-BB41-A41047231982}.Release|x64.Build.0 = Release|x64 {C00B4A26-6C57-4968-AED5-B45FD31A22E7}.Debug|x64.ActiveCfg = Debug|x64 {C00B4A26-6C57-4968-AED5-B45FD31A22E7}.Debug|x64.Build.0 = Debug|x64 {C00B4A26-6C57-4968-AED5-B45FD31A22E7}.Release|x64.ActiveCfg = Release|x64 {C00B4A26-6C57-4968-AED5-B45FD31A22E7}.Release|x64.Build.0 = Release|x64 {C0E811E0-8942-4CFD-A817-74D99E9E6577}.Debug|x64.ActiveCfg = Debug|x64 {C0E811E0-8942-4CFD-A817-74D99E9E6577}.Debug|x64.Build.0 = Debug|x64 {C0E811E0-8942-4CFD-A817-74D99E9E6577}.Release|x64.ActiveCfg = Release|x64 {C0E811E0-8942-4CFD-A817-74D99E9E6577}.Release|x64.Build.0 = Release|x64 {C1C505A8-634D-4640-9DB7-E2B4E59CA2D7}.Debug|x64.ActiveCfg = Debug|x64 {C1C505A8-634D-4640-9DB7-E2B4E59CA2D7}.Debug|x64.Build.0 = Debug|x64 {C1C505A8-634D-4640-9DB7-E2B4E59CA2D7}.Release|x64.ActiveCfg = Release|x64 {C1C505A8-634D-4640-9DB7-E2B4E59CA2D7}.Release|x64.Build.0 = Release|x64 {C2C36D03-26EE-4BD8-8FFC-86CFE16C1218}.Debug|x64.ActiveCfg = Debug|x64 {C2C36D03-26EE-4BD8-8FFC-86CFE16C1218}.Debug|x64.Build.0 = Debug|x64 {C2C36D03-26EE-4BD8-8FFC-86CFE16C1218}.Release|x64.ActiveCfg = Release|x64 {C2C36D03-26EE-4BD8-8FFC-86CFE16C1218}.Release|x64.Build.0 = Release|x64 {C2F94489-A483-4C44-B8A7-11A75F6AEC66}.Debug|x64.ActiveCfg = Debug|x64 {C2F94489-A483-4C44-B8A7-11A75F6AEC66}.Debug|x64.Build.0 = Debug|x64 {C2F94489-A483-4C44-B8A7-11A75F6AEC66}.Release|x64.ActiveCfg = Release|x64 {C2F94489-A483-4C44-B8A7-11A75F6AEC66}.Release|x64.Build.0 = Release|x64 {C3A59B21-A287-4631-B4EC-F4A57D26A14F}.Debug|x64.ActiveCfg = Debug|x64 {C3A59B21-A287-4631-B4EC-F4A57D26A14F}.Debug|x64.Build.0 = Debug|x64 {C3A59B21-A287-4631-B4EC-F4A57D26A14F}.Release|x64.ActiveCfg = Release|x64 {C3A59B21-A287-4631-B4EC-F4A57D26A14F}.Release|x64.Build.0 = Release|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Debug|x64.ActiveCfg = Debug|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Debug|x64.Build.0 = Debug|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Release|x64.ActiveCfg = Release|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Release|x64.Build.0 = Release|x64 {C5E8B8DB-2507-4904-847F-A52196B075F0}.Debug|x64.ActiveCfg = Debug|x64 {C5E8B8DB-2507-4904-847F-A52196B075F0}.Debug|x64.Build.0 = Debug|x64 {C5E8B8DB-2507-4904-847F-A52196B075F0}.Release|x64.ActiveCfg = Release|x64 {C5E8B8DB-2507-4904-847F-A52196B075F0}.Release|x64.Build.0 = Release|x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723}.Debug|x64.ActiveCfg = Debug|x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723}.Release|x64.ActiveCfg = Release|x64 {C71DAF3E-9361-4723-93E2-C475D1D0C0D0}.Debug|x64.ActiveCfg = Debug|x64 {C71DAF3E-9361-4723-93E2-C475D1D0C0D0}.Debug|x64.Build.0 = Debug|x64 {C71DAF3E-9361-4723-93E2-C475D1D0C0D0}.Release|x64.ActiveCfg = Release|x64 {C71DAF3E-9361-4723-93E2-C475D1D0C0D0}.Release|x64.Build.0 = Release|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Debug|x64.ActiveCfg = Debug|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Debug|x64.Build.0 = Debug|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Release|x64.ActiveCfg = Release|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Release|x64.Build.0 = Release|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Debug|x64.ActiveCfg = Debug|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Debug|x64.Build.0 = Debug|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Release|x64.ActiveCfg = Release|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Release|x64.Build.0 = Release|x64 {C96D08A8-AFCD-4C2D-B50F-4582042FCBC1}.Debug|x64.ActiveCfg = Debug|x64 {C96D08A8-AFCD-4C2D-B50F-4582042FCBC1}.Debug|x64.Build.0 = Debug|x64 {C96D08A8-AFCD-4C2D-B50F-4582042FCBC1}.Release|x64.ActiveCfg = Release|x64 {C96D08A8-AFCD-4C2D-B50F-4582042FCBC1}.Release|x64.Build.0 = Release|x64 {C973CD39-D63B-4F5C-BE1D-DED17388B5A4}.Debug|x64.ActiveCfg = Debug|x64 {C973CD39-D63B-4F5C-BE1D-DED17388B5A4}.Debug|x64.Build.0 = Debug|x64 {C973CD39-D63B-4F5C-BE1D-DED17388B5A4}.Release|x64.ActiveCfg = Release|x64 {C973CD39-D63B-4F5C-BE1D-DED17388B5A4}.Release|x64.Build.0 = Release|x64 {CA0F317B-2474-4186-96CA-67F8D7A9D62C}.Debug|x64.ActiveCfg = Debug|x64 {CA0F317B-2474-4186-96CA-67F8D7A9D62C}.Debug|x64.Build.0 = Debug|x64 {CA0F317B-2474-4186-96CA-67F8D7A9D62C}.Release|x64.ActiveCfg = Release|x64 {CA0F317B-2474-4186-96CA-67F8D7A9D62C}.Release|x64.Build.0 = Release|x64 {CA4BBB24-D33E-42E2-A495-F10D80DE8C1D}.Debug|x64.ActiveCfg = Debug|x64 {CA4BBB24-D33E-42E2-A495-F10D80DE8C1D}.Debug|x64.Build.0 = Debug|x64 {CA4BBB24-D33E-42E2-A495-F10D80DE8C1D}.Release|x64.ActiveCfg = Release|x64 {CB906E89-1313-4929-AFF7-86FBF1CC301F}.Debug|x64.ActiveCfg = Debug|x64 {CB906E89-1313-4929-AFF7-86FBF1CC301F}.Debug|x64.Build.0 = Debug|x64 {CB906E89-1313-4929-AFF7-86FBF1CC301F}.Release|x64.ActiveCfg = Release|x64 {CB906E89-1313-4929-AFF7-86FBF1CC301F}.Release|x64.Build.0 = Release|x64 {CCA9B681-D10B-45E4-98CC-531503D2EDE8}.Debug|x64.ActiveCfg = Debug|x64 {CCA9B681-D10B-45E4-98CC-531503D2EDE8}.Debug|x64.Build.0 = Debug|x64 {CCA9B681-D10B-45E4-98CC-531503D2EDE8}.Release|x64.ActiveCfg = Release|x64 {CCA9B681-D10B-45E4-98CC-531503D2EDE8}.Release|x64.Build.0 = Release|x64 {CD4B9690-7A06-4F7A-8492-9336979EE7E9}.Debug|x64.ActiveCfg = Debug|x64 {CD4B9690-7A06-4F7A-8492-9336979EE7E9}.Debug|x64.Build.0 = Debug|x64 {CD4B9690-7A06-4F7A-8492-9336979EE7E9}.Release|x64.ActiveCfg = Release|x64 {CD4B9690-7A06-4F7A-8492-9336979EE7E9}.Release|x64.Build.0 = Release|x64 {CD7A18D5-55D9-4922-A000-FFAA08ABB006}.Debug|x64.ActiveCfg = Debug|x64 {CD7A18D5-55D9-4922-A000-FFAA08ABB006}.Debug|x64.Build.0 = Debug|x64 {CD7A18D5-55D9-4922-A000-FFAA08ABB006}.Release|x64.ActiveCfg = Release|x64 {CD7A18D5-55D9-4922-A000-FFAA08ABB006}.Release|x64.Build.0 = Release|x64 {CDD9DFC6-5C3D-42F7-B822-FE29A1C21752}.Debug|x64.ActiveCfg = Debug|x64 {CDD9DFC6-5C3D-42F7-B822-FE29A1C21752}.Debug|x64.Build.0 = Debug|x64 {CDD9DFC6-5C3D-42F7-B822-FE29A1C21752}.Release|x64.ActiveCfg = Release|x64 {CDD9DFC6-5C3D-42F7-B822-FE29A1C21752}.Release|x64.Build.0 = Release|x64 {CE3F2DFB-8470-4802-AD37-21CAF6CB2681}.Debug|x64.ActiveCfg = Debug|x64 {CE3F2DFB-8470-4802-AD37-21CAF6CB2681}.Debug|x64.Build.0 = Debug|x64 {CE3F2DFB-8470-4802-AD37-21CAF6CB2681}.Release|x64.ActiveCfg = Release|x64 {CE3F2DFB-8470-4802-AD37-21CAF6CB2681}.Release|x64.Build.0 = Release|x64 {CF9A0883-6334-44C7-AC29-349468C78E27}.Debug|x64.ActiveCfg = Debug|x64 {CF9A0883-6334-44C7-AC29-349468C78E27}.Debug|x64.Build.0 = Debug|x64 {CF9A0883-6334-44C7-AC29-349468C78E27}.Release|x64.ActiveCfg = Release|x64 {CF9A0883-6334-44C7-AC29-349468C78E27}.Release|x64.Build.0 = Release|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Debug|x64.ActiveCfg = Debug|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Debug|x64.Build.0 = Debug|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Release|x64.ActiveCfg = Release|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Release|x64.Build.0 = Release|x64 {D28F5FF6-8401-4E0D-94F9-3A1FD7ED64E3}.Debug|x64.ActiveCfg = Debug|x64 {D28F5FF6-8401-4E0D-94F9-3A1FD7ED64E3}.Debug|x64.Build.0 = Debug|x64 {D28F5FF6-8401-4E0D-94F9-3A1FD7ED64E3}.Release|x64.ActiveCfg = Release|x64 {D28F5FF6-8401-4E0D-94F9-3A1FD7ED64E3}.Release|x64.Build.0 = Release|x64 {D2C30C7E-A7D3-487A-956E-418CECAFFE8E}.Debug|x64.ActiveCfg = Debug|x64 {D2C30C7E-A7D3-487A-956E-418CECAFFE8E}.Debug|x64.Build.0 = Debug|x64 {D2C30C7E-A7D3-487A-956E-418CECAFFE8E}.Release|x64.ActiveCfg = Release|x64 {D2C30C7E-A7D3-487A-956E-418CECAFFE8E}.Release|x64.Build.0 = Release|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Debug|x64.ActiveCfg = Debug|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Debug|x64.Build.0 = Debug|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Release|x64.ActiveCfg = Release|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Release|x64.Build.0 = Release|x64 {D4035736-1AD6-4100-9FA9-A8A0C1DAE0C7}.Debug|x64.ActiveCfg = Debug|x64 {D4035736-1AD6-4100-9FA9-A8A0C1DAE0C7}.Debug|x64.Build.0 = Debug|x64 {D4035736-1AD6-4100-9FA9-A8A0C1DAE0C7}.Release|x64.ActiveCfg = Release|x64 {D4035736-1AD6-4100-9FA9-A8A0C1DAE0C7}.Release|x64.Build.0 = Release|x64 {D5093EC2-5B5A-4D79-842C-6A1481E9C989}.Debug|x64.ActiveCfg = Debug {D5093EC2-5B5A-4D79-842C-6A1481E9C989}.Debug|x64.Build.0 = Debug {D5093EC2-5B5A-4D79-842C-6A1481E9C989}.Release|x64.ActiveCfg = Release {D5093EC2-5B5A-4D79-842C-6A1481E9C989}.Release|x64.Build.0 = Release {D829DB63-E046-474D-8EA3-43A6659294D8}.Debug|x64.ActiveCfg = Debug|x64 {D829DB63-E046-474D-8EA3-43A6659294D8}.Debug|x64.Build.0 = Debug|x64 {D829DB63-E046-474D-8EA3-43A6659294D8}.Release|x64.ActiveCfg = Release|x64 {D829DB63-E046-474D-8EA3-43A6659294D8}.Release|x64.Build.0 = Release|x64 {D8317F1D-7A70-4A39-977A-EAB05A04A87B}.Debug|x64.ActiveCfg = Debug|x64 {D8317F1D-7A70-4A39-977A-EAB05A04A87B}.Debug|x64.Build.0 = Debug|x64 {D8317F1D-7A70-4A39-977A-EAB05A04A87B}.Release|x64.ActiveCfg = Release|x64 {D8317F1D-7A70-4A39-977A-EAB05A04A87B}.Release|x64.Build.0 = Release|x64 {D88187D2-1977-4C5F-B0CD-83C69BD6C1BC}.Debug|x64.ActiveCfg = Debug|x64 {D88187D2-1977-4C5F-B0CD-83C69BD6C1BC}.Debug|x64.Build.0 = Debug|x64 {D88187D2-1977-4C5F-B0CD-83C69BD6C1BC}.Release|x64.ActiveCfg = Release|x64 {D88187D2-1977-4C5F-B0CD-83C69BD6C1BC}.Release|x64.Build.0 = Release|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Debug|x64.ActiveCfg = Debug|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Debug|x64.Build.0 = Debug|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Release|x64.ActiveCfg = Release|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Release|x64.Build.0 = Release|x64 {DB12B063-B09B-4D74-B293-F00A72D07BB2}.Debug|x64.ActiveCfg = Debug|x64 {DB12B063-B09B-4D74-B293-F00A72D07BB2}.Debug|x64.Build.0 = Debug|x64 {DB12B063-B09B-4D74-B293-F00A72D07BB2}.Release|x64.ActiveCfg = Release|x64 {DB12B063-B09B-4D74-B293-F00A72D07BB2}.Release|x64.Build.0 = Release|x64 {DB68AB21-510B-4BA1-9E6F-E5731D8647BC}.Debug|x64.ActiveCfg = Debug|x64 {DB68AB21-510B-4BA1-9E6F-E5731D8647BC}.Debug|x64.Build.0 = Debug|x64 {DB68AB21-510B-4BA1-9E6F-E5731D8647BC}.Release|x64.ActiveCfg = Release|x64 {DB68AB21-510B-4BA1-9E6F-E5731D8647BC}.Release|x64.Build.0 = Release|x64 {DFEBEBAA-9624-445C-82A0-93363E22D806}.Debug|x64.ActiveCfg = Debug|x64 {DFEBEBAA-9624-445C-82A0-93363E22D806}.Debug|x64.Build.0 = Debug|x64 {DFEBEBAA-9624-445C-82A0-93363E22D806}.Release|x64.ActiveCfg = Release|x64 {DFEBEBAA-9624-445C-82A0-93363E22D806}.Release|x64.Build.0 = Release|x64 {E4E2EC33-7902-45D0-9C3C-ADBAFA46874A}.Debug|x64.ActiveCfg = Debug|x64 {E4E2EC33-7902-45D0-9C3C-ADBAFA46874A}.Debug|x64.Build.0 = Debug|x64 {E4E2EC33-7902-45D0-9C3C-ADBAFA46874A}.Release|x64.ActiveCfg = Release|x64 {E4E2EC33-7902-45D0-9C3C-ADBAFA46874A}.Release|x64.Build.0 = Release|x64 {E648732D-78FA-427A-928C-9A59222D37B7}.Debug|x64.ActiveCfg = Debug|x64 {E648732D-78FA-427A-928C-9A59222D37B7}.Debug|x64.Build.0 = Debug|x64 {E648732D-78FA-427A-928C-9A59222D37B7}.Release|x64.ActiveCfg = Release|x64 {E648732D-78FA-427A-928C-9A59222D37B7}.Release|x64.Build.0 = Release|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Debug|x64.ActiveCfg = Debug|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Debug|x64.Build.0 = Debug|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Release|x64.ActiveCfg = Release|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Release|x64.Build.0 = Release|x64 {E7691F81-86EF-467D-82E1-F5B9416386F9}.Debug|x64.ActiveCfg = Debug|x64 {E7691F81-86EF-467D-82E1-F5B9416386F9}.Debug|x64.Build.0 = Debug|x64 {E7691F81-86EF-467D-82E1-F5B9416386F9}.Release|x64.ActiveCfg = Release|x64 {E7691F81-86EF-467D-82E1-F5B9416386F9}.Release|x64.Build.0 = Release|x64 {E796AA20-D664-4D05-ABD9-C93A4FBE3E5C}.Debug|x64.ActiveCfg = Debug|x64 {E796AA20-D664-4D05-ABD9-C93A4FBE3E5C}.Debug|x64.Build.0 = Debug|x64 {E796AA20-D664-4D05-ABD9-C93A4FBE3E5C}.Release|x64.ActiveCfg = Release|x64 {E796AA20-D664-4D05-ABD9-C93A4FBE3E5C}.Release|x64.Build.0 = Release|x64 {E901B756-EA72-4B8D-967F-85F109D0D1DE}.Debug|x64.ActiveCfg = Debug|x64 {E901B756-EA72-4B8D-967F-85F109D0D1DE}.Debug|x64.Build.0 = Debug|x64 {E901B756-EA72-4B8D-967F-85F109D0D1DE}.Release|x64.ActiveCfg = Release|x64 {E901B756-EA72-4B8D-967F-85F109D0D1DE}.Release|x64.Build.0 = Release|x64 {E9E079D6-25BF-46E3-8075-7D733303DD59}.Debug|x64.ActiveCfg = Debug|x64 {E9E079D6-25BF-46E3-8075-7D733303DD59}.Debug|x64.Build.0 = Debug|x64 {E9E079D6-25BF-46E3-8075-7D733303DD59}.Release|x64.ActiveCfg = Release|x64 {E9E079D6-25BF-46E3-8075-7D733303DD59}.Release|x64.Build.0 = Release|x64 {ED2A831F-4AAF-4CF7-A953-3C45B0EC1BE6}.Debug|x64.ActiveCfg = Debug|x64 {ED2A831F-4AAF-4CF7-A953-3C45B0EC1BE6}.Debug|x64.Build.0 = Debug|x64 {ED2A831F-4AAF-4CF7-A953-3C45B0EC1BE6}.Release|x64.ActiveCfg = Release|x64 {ED2A831F-4AAF-4CF7-A953-3C45B0EC1BE6}.Release|x64.Build.0 = Release|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Debug|x64.ActiveCfg = Debug|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Debug|x64.Build.0 = Debug|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Release|x64.ActiveCfg = Release|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Release|x64.Build.0 = Release|x64 {F0B613C4-1D9A-4259-BD0E-C1B9FF2AA3A0}.Debug|x64.ActiveCfg = Debug|x64 {F0B613C4-1D9A-4259-BD0E-C1B9FF2AA3A0}.Debug|x64.Build.0 = Debug|x64 {F0B613C4-1D9A-4259-BD0E-C1B9FF2AA3A0}.Release|x64.ActiveCfg = Release|x64 {F0B613C4-1D9A-4259-BD0E-C1B9FF2AA3A0}.Release|x64.Build.0 = Release|x64 {F13108C4-4C86-4D56-A317-A4E5892A8AF7}.Debug|x64.ActiveCfg = Debug|x64 {F13108C4-4C86-4D56-A317-A4E5892A8AF7}.Debug|x64.Build.0 = Debug|x64 {F13108C4-4C86-4D56-A317-A4E5892A8AF7}.Release|x64.ActiveCfg = Release|x64 {F13108C4-4C86-4D56-A317-A4E5892A8AF7}.Release|x64.Build.0 = Release|x64 {F322ED35-A389-4B65-AC8A-E25F1337DBCC}.Debug|x64.ActiveCfg = Debug|x64 {F322ED35-A389-4B65-AC8A-E25F1337DBCC}.Debug|x64.Build.0 = Debug|x64 {F322ED35-A389-4B65-AC8A-E25F1337DBCC}.Release|x64.ActiveCfg = Release|x64 {F322ED35-A389-4B65-AC8A-E25F1337DBCC}.Release|x64.Build.0 = Release|x64 {F3E5650D-834E-45E6-90C7-3FC2AA954929}.Debug|x64.ActiveCfg = Debug|x64 {F3E5650D-834E-45E6-90C7-3FC2AA954929}.Debug|x64.Build.0 = Debug|x64 {F3E5650D-834E-45E6-90C7-3FC2AA954929}.Release|x64.ActiveCfg = Release|x64 {F3E5650D-834E-45E6-90C7-3FC2AA954929}.Release|x64.Build.0 = Release|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Debug|x64.ActiveCfg = Debug|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Debug|x64.Build.0 = Debug|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Release|x64.ActiveCfg = Release|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Release|x64.Build.0 = Release|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Debug|x64.ActiveCfg = Debug|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Debug|x64.Build.0 = Debug|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Release|x64.ActiveCfg = Release|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Release|x64.Build.0 = Release|x64 {F63FB47F-1DCE-48E5-9CBD-F3E0A354472B}.Debug|x64.ActiveCfg = Debug|x64 {F63FB47F-1DCE-48E5-9CBD-F3E0A354472B}.Debug|x64.Build.0 = Debug|x64 {F63FB47F-1DCE-48E5-9CBD-F3E0A354472B}.Release|x64.ActiveCfg = Release|x64 {F63FB47F-1DCE-48E5-9CBD-F3E0A354472B}.Release|x64.Build.0 = Release|x64 {F7C6C6B6-4142-4C82-8699-4A9D8183181B}.Debug|x64.ActiveCfg = Debug|x64 {F7C6C6B6-4142-4C82-8699-4A9D8183181B}.Debug|x64.Build.0 = Debug|x64 {F7C6C6B6-4142-4C82-8699-4A9D8183181B}.Release|x64.ActiveCfg = Release|x64 {F7C6C6B6-4142-4C82-8699-4A9D8183181B}.Release|x64.Build.0 = Release|x64 {FB2D2B18-E616-4639-8593-0E1AF2DA01A8}.Debug|x64.ActiveCfg = Debug|x64 {FB2D2B18-E616-4639-8593-0E1AF2DA01A8}.Debug|x64.Build.0 = Debug|x64 {FB2D2B18-E616-4639-8593-0E1AF2DA01A8}.Release|x64.ActiveCfg = Release|x64 {FB2D2B18-E616-4639-8593-0E1AF2DA01A8}.Release|x64.Build.0 = Release|x64 {FB6AFFAA-0279-41F7-A698-F81C90BBD987}.Debug|x64.ActiveCfg = Debug|x64 {FB6AFFAA-0279-41F7-A698-F81C90BBD987}.Debug|x64.Build.0 = Debug|x64 {FB6AFFAA-0279-41F7-A698-F81C90BBD987}.Release|x64.ActiveCfg = Release|x64 {FB6AFFAA-0279-41F7-A698-F81C90BBD987}.Release|x64.Build.0 = Release|x64 {FBB77433-639E-42DC-9355-EA94CAE294D2}.Debug|x64.ActiveCfg = Debug|x64 {FBB77433-639E-42DC-9355-EA94CAE294D2}.Debug|x64.Build.0 = Debug|x64 {FBB77433-639E-42DC-9355-EA94CAE294D2}.Release|x64.ActiveCfg = Release|x64 {FBB77433-639E-42DC-9355-EA94CAE294D2}.Release|x64.Build.0 = Release|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Debug|x64.ActiveCfg = Debug|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Debug|x64.Build.0 = Debug|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Release|x64.ActiveCfg = Release|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Release|x64.Build.0 = Release|x64 {FD726AA3-D4FA-4597-B435-08CC7752888C}.Debug|x64.ActiveCfg = Debug|x64 {FD726AA3-D4FA-4597-B435-08CC7752888C}.Debug|x64.Build.0 = Debug|x64 {FD726AA3-D4FA-4597-B435-08CC7752888C}.Release|x64.ActiveCfg = Release|x64 {FD726AA3-D4FA-4597-B435-08CC7752888C}.Release|x64.Build.0 = Release|x64 {FD86DEA2-449E-44CD-A014-BFC30ED3FDF2}.Debug|x64.ActiveCfg = Debug|x64 {FD86DEA2-449E-44CD-A014-BFC30ED3FDF2}.Debug|x64.Build.0 = Debug|x64 {FD86DEA2-449E-44CD-A014-BFC30ED3FDF2}.Release|x64.ActiveCfg = Release|x64 {FD86DEA2-449E-44CD-A014-BFC30ED3FDF2}.Release|x64.Build.0 = Release|x64 {FEA09B48-34C2-4963-8A5A-F97BDA136D72}.Debug|x64.ActiveCfg = Debug|x64 {FEA09B48-34C2-4963-8A5A-F97BDA136D72}.Debug|x64.Build.0 = Debug|x64 {FEA09B48-34C2-4963-8A5A-F97BDA136D72}.Release|x64.ActiveCfg = Release|x64 {FEA09B48-34C2-4963-8A5A-F97BDA136D72}.Release|x64.Build.0 = Release|x64 {FF374D62-CBCF-401E-9A02-1D3DB8BE16E4}.Debug|x64.ActiveCfg = Debug|x64 {FF374D62-CBCF-401E-9A02-1D3DB8BE16E4}.Debug|x64.Build.0 = Debug|x64 {FF374D62-CBCF-401E-9A02-1D3DB8BE16E4}.Release|x64.ActiveCfg = Release|x64 {FF374D62-CBCF-401E-9A02-1D3DB8BE16E4}.Release|x64.Build.0 = Release|x64 {FF6E5B0C-DC00-4C93-B9C2-63D1E858BA79}.Debug|x64.ActiveCfg = Debug|x64 {FF6E5B0C-DC00-4C93-B9C2-63D1E858BA79}.Debug|x64.Build.0 = Debug|x64 {FF6E5B0C-DC00-4C93-B9C2-63D1E858BA79}.Release|x64.ActiveCfg = Release|x64 {FF6E5B0C-DC00-4C93-B9C2-63D1E858BA79}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {025E7D51-41F2-4CBA-956E-C37A4443DB1B} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {0287C3DC-AE03-4714-AAFF-C52F062ECA6F} = {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} {02BC3B44-C7F1-4793-86C1-6F36CA8A7F53} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {0388E945-A655-41A7-AF27-8981CEE0E49A} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {04345B7D-B0A1-405B-8BB2-5B98A3400FEF} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {0529575C-F6E8-44FD-BB82-82A29948D0F2} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {063037B2-CA35-4520-811C-19D9C4ED891E} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {06877FED-15BA-421F-85C9-1A964FB97446} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {06FCFDE9-8C88-4B7D-B87A-47953DB203C9} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {0703E813-9CC8-4DEA-AA33-42B099CD172D} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {07A153D9-DF17-4DE8-A3C2-EBF171B961AE} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {08762559-E9DF-475B-BA99-49F4B5A1D80B} = {853D45D8-980C-4991-B62A-DAC6FD245402} {08B62E36-63D2-4FF1-A605-4BBABAEE73FB} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {0A049EAD-652F-4E20-8026-90FD99AEE77A} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {0B1818EB-BDC8-4865-964F-DB8BF05CFD86} = {853D45D8-980C-4991-B62A-DAC6FD245402} {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03} = {BFEDF709-A700-4769-9056-ACA934D828A8} {0CC6D525-806E-433F-AB4A-6CFD546418B1} = {853D45D8-980C-4991-B62A-DAC6FD245402} {0CDCEB97-3270-4939-A290-EA2D3BE34B0C} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {0DC1B184-C814-448F-8B5F-CFFA6F05156C} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {0FB8F0FD-276C-413B-97A8-67ABE0C9043B} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {10469175-EEF7-44A0-9961-AC4E45EFD800} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {11D76FBC-DFAA-4B31-9DB0-206E171E3F94} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {11E158AE-C85A-4A6E-B66A-ED2994709276} = {F09A0864-9221-47AD-872F-D4538104D747} {12A1A3EF-202C-4DD0-9B5A-F5126CAB078F} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {1464398A-100F-4518-BDB9-939A6362B6CF} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {16721958-ECE3-4674-9913-9AF8E32F0CD8} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {179BEB5A-2C90-44F5-A734-FA756A5E668C} = {F09A0864-9221-47AD-872F-D4538104D747} {17A4B817-68B1-4719-A9EF-BD8FAB747DE6} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {18E90E1A-F2E0-40DF-9900-A14E560C9EB4} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {1A36B57B-2E88-4D81-89C0-F575C9895E36} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {1B871BA2-3F70-4BC9-9DF4-725EB07F6628} = {F09A0864-9221-47AD-872F-D4538104D747} {1B9B0D6D-E530-44A6-ADAE-09EA2BDC47DE} = {E23BB160-006E-44F2-8FB4-3A2240BBC20C} {1BA340EC-B0B2-438D-A47C-27F86F604133} = {853D45D8-980C-4991-B62A-DAC6FD245402} {1BAA1617-93AE-4196-8A1A-BD492FB18AEF} = {853D45D8-980C-4991-B62A-DAC6FD245402} {1E564DB1-0687-4CC4-BAE5-453F93052FDA} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {1EB3DE5B-6357-498D-8CAC-EEC0209EA454} = {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} {1F2E1C51-2B14-4047-BE6D-52E00FC3C780} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {21991E84-7859-420E-ADDA-1D058E787F06} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {22DCCD3E-79FF-4F66-A9AA-D033A7671B94} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {2498FCDA-E2CC-43EF-9A35-8CD63F253171} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {25B5C601-03D7-4861-9C0F-7F0453B04227} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {26135DD1-8BB0-4217-A4DC-C1F232F35BA2} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {26166DF1-3C94-44AF-9075-BA31DCD2F6BB} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {26D24B3D-22CE-44EB-AA21-2BF594F80520} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {27FA11C6-431D-41D1-A417-FAB7C4F93DCA} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {296F3C5D-3951-423E-8E2F-FD4A37958C72} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {29D9376B-DC36-4940-83F1-A7CBE38A2103} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {2A1D6AF2-7336-4966-A4B3-0BE9A24BAE00} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {2B1A5104-A324-4D02-B5C7-D021FB8F880C} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {2B7772E6-9DAA-4F38-B0BC-7B2399366325} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {2DE6B085-3C19-49B1-894A-AD9376000E09} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {2E7E8487-0BB0-4E8A-8672-ED8ABD80D468} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {2ED26FDA-3C4E-4514-B387-5E77C302FF71} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {2EFFC590-BF5E-46A2-AF04-E67E1D571D2E} = {F09A0864-9221-47AD-872F-D4538104D747} {2F543422-4B8A-4898-BE6B-590F52B4E9D1} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {3142CB13-CADA-48D3-9A25-E6ACB243760A} = {F09A0864-9221-47AD-872F-D4538104D747} {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {3B23831B-E5DE-4A62-9D0B-27D0D9F293F4} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {3BAB8FDF-42F7-4D46-AA10-E282FD41B9F2} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {3CF270CD-0F56-48E3-AD84-82F369C568BF} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {3D5A802D-CFAF-4C33-A042-D79851F60356} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {3D9A580B-5F0F-434F-B4D6-228B8E7ADAA5} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {3DEB4FBF-638D-4588-A510-E9A77FF75BB1} = {3D5A802D-CFAF-4C33-A042-D79851F60356} {3EC30D6A-BDA4-4971-879A-8814204EAE31} = {F09A0864-9221-47AD-872F-D4538104D747} {3ECCB0F1-3ADF-486A-91C5-79DF0FC22F78} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {3ED56E55-84A6-422C-A8D4-A8439FB8F245} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {40DC66AD-F66D-4194-B9A4-A3A2222516FE} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {42CCEF95-5ADD-460C-967E-DD5B2C744943} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {433F7840-C597-4950-84C9-E4FF7DF6A298} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {45027FC5-4A32-47BD-AC5B-66CC7616B1D2} = {9A8482A7-BF0C-423D-8266-189456ED41F6} {45E74E38-35CA-4CB6-8965-BC20D39659AF} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {4850F425-9128-4E91-973C-5AE7BD97395B} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {48A3AE10-200B-454E-9D82-EC1A88CF1151} = {E23BB160-006E-44F2-8FB4-3A2240BBC20C} {492BAA3D-0D5D-478E-9765-500463AE69AA} = {853D45D8-980C-4991-B62A-DAC6FD245402} {49A7CC5A-D5E7-4A07-917F-C6918B982BE8} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {4A3CDA9F-55C2-455E-8E82-1FAAAA2245C5} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {4C291EEB-3874-4724-9CC2-1335D13FF0EE} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {4C429783-0B01-449F-A36F-C2019233890B} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {4C6E7F0A-7E6A-4713-B1D2-B7B4ADC992AF} = {F09A0864-9221-47AD-872F-D4538104D747} {4E334022-7A71-4197-9E15-878F7EFC877E} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {4ED1E400-CF16-48C2-B176-2BF186E73531} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {4FB4FF90-4E92-4CFB-A01F-C73D6861CA03} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {50FD1E47-2131-48D2-9435-5CB28DF6B15A} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {513C4CFA-BD5B-4470-BA93-F6D43778A754} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {537F759B-B617-48D9-A2F3-7FB769A8F9B7} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {54E6F8F5-418E-44BE-8DF2-5A60D9EE971B} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {5580D11C-FDA6-4CF2-A0E8-1C2D3FBC11F1} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {581B3A58-F3F0-4765-91E5-D0C82816A528} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {58386481-30B7-40FC-96AF-0723A4A7B228} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {59AB6976-D16B-48D0-8D16-94360D3FE51D} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {59D7A9CD-9912-40E4-96E1-8A873F777F62} = {6D63CDF1-F62C-4614-AD8A-95B0A63AA070} {5A391A14-8E29-4788-93FC-EDADED31D32F} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {5AD07646-5E16-4CEF-B80A-BE5EE4D54FEF} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {5D362DB7-D2BD-4907-AAD8-4B8627E72282} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {5DB2E259-0D19-4A89-B8EC-B2912F39924D} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {5F2B687A-1B42-439C-AEEC-135DD22FB851} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {5F8A56F8-2C5B-48B6-9654-DD642D3E5F5C} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {60206D22-E132-4695-8486-10BECA32C5CC} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {6068773F-FDA7-484F-8650-EE1AA5C3CB37} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {60B463D4-8CD5-4BF6-A25B-01BE13B87590} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {628FADA9-7047-4DD9-BD17-9FE4B5A1ADB0} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {63B8184D-85E0-4E6A-9729-558C567D1D1D} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {643B82A1-D009-46A9-92A0-2883399B05C2} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {6516D6CF-8000-4341-9487-312BC83EE370} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {65D92D98-97E1-48F7-AEF6-75221CF48EA4} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {673277EC-D26B-414D-92E3-84EE873316A8} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {67AC1343-98FD-4143-92C0-559C55F749F5} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {6851356E-A5D9-46A6-8262-A7E208729F18} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {6AE1B8BE-D46A-4E99-87A2-F160FB950DCA} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {6B492754-9F80-44B3-A2A7-1D98AF06F3B2} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {6BCEF2A5-0CEC-4CC6-9CB0-D3FBF871A408} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {6D63CDF1-F62C-4614-AD8A-95B0A63AA070} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {6D7C1169-3246-465F-B630-ECFEF4F3179A} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {6F06A19B-0921-4B71-A3A5-B350B5FFEADB} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {6F4953DA-FDC3-46CF-BF24-3752CCF2E1CB} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {70EE1D40-0C65-4985-8EFC-BD40EE3A89B2} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {715EADD7-0FFE-4F1F-94E7-49302968DF79} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {718CA6FA-6446-4E43-83DF-BA4E85E5886B} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {71D182E0-345A-4375-B0FA-3536821B0EE3} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {72598DD9-3F44-4E6A-B0B7-C5AE3FF43B1F} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {7264C8F6-73FB-4830-9306-1558D3EAC71B} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {729E3905-FF7D-49C5-9871-6D35D839183E} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF} = {6D63CDF1-F62C-4614-AD8A-95B0A63AA070} {73F35C28-811C-4D77-916E-386EB139C001} = {3D5A802D-CFAF-4C33-A042-D79851F60356} {74243B75-816C-4077-8DF0-98D2C78B0E5D} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {746BA101-5C93-42A5-AC7A-64DCEB186572} = {853D45D8-980C-4991-B62A-DAC6FD245402} {74D655D5-F661-4887-A1EB-5A6222AF5FCA} = {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} {774627B7-6532-4464-AEE4-02F72CA44F95} = {9A8482A7-BF0C-423D-8266-189456ED41F6} {779425B1-2211-499B-A7CC-4F9EC6CB0D25} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {7D71EE07-6CE2-49FA-8AB8-976800A050A0} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {7DC3B3DD-73ED-4602-9AF3-8D7053620DEA} = {877E7D1D-8150-4FE5-A139-B6FBCEAEC393} {7DFEB4A5-8B04-4302-9D09-8144918FCF81} = {E23BB160-006E-44F2-8FB4-3A2240BBC20C} {7E0106F8-A597-48D5-B4F2-E0FC4D95EE95} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {7F51CD29-3BCD-4DD8-B327-F384B5A616D1} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {8008010F-8718-4C5F-86B2-195AEBF73422} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {8010BBB0-C71B-4EFF-95EB-65C01E5EC197} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {80AF1B7D-B8CE-4AF0-AE3B-1DABED1B57E7} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {8145F442-0EF6-4E55-BAED-8DDE72022355} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {85D4076B-896B-4EBB-8F3A-8B44C24CD452} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {85DBDA9B-AEF6-43E7-B8B5-05FF2BEC61A3} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {86EE22CC-6D3C-4F81-ADC8-394946F0DA81} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {877E7D1D-8150-4FE5-A139-B6FBCEAEC393} = {853D45D8-980C-4991-B62A-DAC6FD245402} {88D239E4-EB7D-4E0A-BE3A-AD78B9F408FC} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {89B6AF14-08A0-437A-B31D-A8A3492FA965} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {89F947CA-DDEF-4131-8AFB-584ABA4A1302} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {8A0FA780-068A-4534-AA2F-4FF4CF977AF2} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {8A4872D7-A234-4B9B-8215-82C6BB15F3A2} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {8C42CA7C-1543-4F1B-A55F-28CD419C7D35} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {8C6D73E0-0A6F-4487-A040-0EC78D7D6D9A} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {8CD79300-941F-4FDD-A371-92BF0EFBA0FC} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {8D6BB292-9E1C-413D-9F98-4864BDC1514A} = {853D45D8-980C-4991-B62A-DAC6FD245402} {8D75FA1A-EC74-4F88-8AC1-CE3F98E4D828} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {8DB4158E-96EE-4DE5-A425-C9638F50B9ED} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} {8E374371-30E1-4623-8755-2A2F3742170B} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {8F42055F-FFD9-4B10-B266-6DD32923F0AC} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {95FAF291-03D1-42FC-9C10-424D551D475D} {90C5FCF1-8243-4988-A4EA-AA6A88268373} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {91365DAC-BF62-4B96-919D-7C474D029B61} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {9186EAC4-2F34-4F17-B940-6585D7869BCD} = {95FAF291-03D1-42FC-9C10-424D551D475D} {91C30620-70CA-46C7-AC71-71F3C602690E} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {91E19AEB-7B75-43E0-B8B4-D2BB60D839EA} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {92388A20-50FC-45F8-89E3-71F1618EFABB} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {924B2937-0B53-4DC6-B7E1-5F3102728F89} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {940C5974-9EF3-4FAC-9820-976B0711F69B} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {95B683BD-B9DC-400F-9BC0-8F1505F08BF5} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {95FAF291-03D1-42FC-9C10-424D551D475D} = {853D45D8-980C-4991-B62A-DAC6FD245402} {96D00A19-5CEF-4CC5-BDE8-E33C68BCE90F} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {98ACBE5D-1A92-46F9-AA81-533412172952} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {9935E8A1-F3F9-41D4-BD81-AD3FD04642E9} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {99F7F00F-1DE5-45EA-992B-64BA282FAC76} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {9A4078F8-B8E4-4EC6-A6FF-4F29DAD9CE48} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {9A8482A7-BF0C-423D-8266-189456ED41F6} = {95FAF291-03D1-42FC-9C10-424D551D475D} {9AE2DAF9-10C4-4EC3-AE52-AD5EE9C77C55} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {9C37B8CC-F810-4787-924D-65BC227091A3} = {853D45D8-980C-4991-B62A-DAC6FD245402} {9D1C3F29-1268-4241-BEFB-89D2859C62D3} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} {9D9E33EB-4C24-4646-A3FB-35DA17247917} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {9E9E3D25-2139-4A5D-9200-18148DDEAD45} = {853D45D8-980C-4991-B62A-DAC6FD245402} {9FF51F3E-AF36-4F45-A797-C5F03A090298} = {91C30620-70CA-46C7-AC71-71F3C602690E} {9FF62356-30B4-42A1-8DC7-45262A18DD44} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {A216BF23-FC5C-4426-BF20-8568A2AA5FA0} = {F09A0864-9221-47AD-872F-D4538104D747} {A2A0FAEA-2B7C-4FC3-B904-1DB4DEACF88D} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {A2DEA0DC-04F3-4384-BCC2-F7EE2CFD6EE7} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {A38EFCDB-53D6-4474-97F3-0DDC6CE70D76} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {A5794EFF-8232-4E2B-B52C-908823048F54} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {A57D9365-172E-4782-ADC6-82A594E30943} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {A5DF0746-5496-4C29-9CCD-5FA76604BF8B} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {A6CC801B-CF30-4703-BC54-3E21F90B787D} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2} = {91C30620-70CA-46C7-AC71-71F3C602690E} {A911D62B-9D48-4807-B183-7127F1AC7A83} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {AB15A115-E429-4123-BEBF-206FBA4CF615} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {ABD4B53D-94CD-4C6A-B30A-CB6FEBA16296} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {AE9E908D-BAEC-491F-9914-436B3CE35E94} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {AEAA72CD-E060-417C-9CA1-49B4738384E0} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {AF0B7480-EBE3-486B-B0C8-134910BC9324} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {B2DC2F89-0724-4110-8934-D1173BD73D44} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {B30C6212-A160-405A-8FE7-340E721738A2} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {B35BFA09-DE68-483B-AB61-8790E8F060A8} = {F09A0864-9221-47AD-872F-D4538104D747} {B36EE2A8-1487-47BB-B3B9-ABCB732B35F3} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {B36F115C-8139-4C35-A3E7-E6BF9F3DA793} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {B379539C-E130-460D-AE82-4EBDD1A97845} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {B440BB05-37A8-42EA-98D3-D83EB113E497} = {E23BB160-006E-44F2-8FB4-3A2240BBC20C} {B6DA6617-D98F-4A4D-A7C4-A317212924BF} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {B6F4B85D-FE55-4A1B-AE97-D4A9ECFE195F} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {B775480C-5B32-4F64-B026-47367280EC56} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {B870D8A6-12CD-4DD0-B843-833695C2310A} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {B887EA26-846C-4D6A-B0E4-432487506BC7} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {BABC6427-E533-4DCF-91E3-B5B2ED253F46} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {BAE107BA-7618-4972-8188-2D3CDAAE0453} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {BB248BAC-6E1B-433C-A254-75140A273AB5} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {BF3B6C3A-3073-4AD4-BB41-A41047231982} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {BFEDF709-A700-4769-9056-ACA934D828A8} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {C00B4A26-6C57-4968-AED5-B45FD31A22E7} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {C0E811E0-8942-4CFD-A817-74D99E9E6577} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {C1C505A8-634D-4640-9DB7-E2B4E59CA2D7} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {C2C36D03-26EE-4BD8-8FFC-86CFE16C1218} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {C2F94489-A483-4C44-B8A7-11A75F6AEC66} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {C3A59B21-A287-4631-B4EC-F4A57D26A14F} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {C3CEE34C-29E0-4A22-B258-3FBAF662AA19} = {91C30620-70CA-46C7-AC71-71F3C602690E} {C5E8B8DB-2507-4904-847F-A52196B075F0} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {C6E9D8C2-D5C1-441B-95ED-378E10DC5723} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {C71DAF3E-9361-4723-93E2-C475D1D0C0D0} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {C84633F5-05B1-4AC1-A074-104D1DB2A91E} = {EA0D2458-5FCD-4DAB-B07D-229327B98BEB} {C96D08A8-AFCD-4C2D-B50F-4582042FCBC1} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {C973CD39-D63B-4F5C-BE1D-DED17388B5A4} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {CA0F317B-2474-4186-96CA-67F8D7A9D62C} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {CA4BBB24-D33E-42E2-A495-F10D80DE8C1D} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {CB906E89-1313-4929-AFF7-86FBF1CC301F} = {9C37B8CC-F810-4787-924D-65BC227091A3} {CCA9B681-D10B-45E4-98CC-531503D2EDE8} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {CD4B9690-7A06-4F7A-8492-9336979EE7E9} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {CD7A18D5-55D9-4922-A000-FFAA08ABB006} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {CDD9DFC6-5C3D-42F7-B822-FE29A1C21752} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {CE3F2DFB-8470-4802-AD37-21CAF6CB2681} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {CF9A0883-6334-44C7-AC29-349468C78E27} = {853D45D8-980C-4991-B62A-DAC6FD245402} {D062166F-0EC7-4C13-A772-0C7157EEFE41} = {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} {D28F5FF6-8401-4E0D-94F9-3A1FD7ED64E3} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {D2C30C7E-A7D3-487A-956E-418CECAFFE8E} = {F09A0864-9221-47AD-872F-D4538104D747} {D3A99F36-4B72-4766-ABCD-CCEDC26DD139} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {D4035736-1AD6-4100-9FA9-A8A0C1DAE0C7} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {D5093EC2-5B5A-4D79-842C-6A1481E9C989} = {52B4C136-F527-4FE0-9781-5B2259A0FF27} {D829DB63-E046-474D-8EA3-43A6659294D8} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {D8317F1D-7A70-4A39-977A-EAB05A04A87B} = {E23BB160-006E-44F2-8FB4-3A2240BBC20C} {D88187D2-1977-4C5F-B0CD-83C69BD6C1BC} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {D93A2683-6D99-4F18-B378-91195D23E007} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {DB12B063-B09B-4D74-B293-F00A72D07BB2} = {16721958-ECE3-4674-9913-9AF8E32F0CD8} {DB68AB21-510B-4BA1-9E6F-E5731D8647BC} = {BFBAB433-860E-4A28-96E3-A4B7AFE3B297} {DFEBEBAA-9624-445C-82A0-93363E22D806} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {E23BB160-006E-44F2-8FB4-3A2240BBC20C} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {E4E2EC33-7902-45D0-9C3C-ADBAFA46874A} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {E648732D-78FA-427A-928C-9A59222D37B7} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {E68DEB59-C709-4945-AF80-EEBCADDED944} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {E7691F81-86EF-467D-82E1-F5B9416386F9} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {E796AA20-D664-4D05-ABD9-C93A4FBE3E5C} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {E901B756-EA72-4B8D-967F-85F109D0D1DE} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {E9E079D6-25BF-46E3-8075-7D733303DD59} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {EA0D2458-5FCD-4DAB-B07D-229327B98BEB} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {ED2A831F-4AAF-4CF7-A953-3C45B0EC1BE6} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {F09A0864-9221-47AD-872F-D4538104D747} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {F0B613C4-1D9A-4259-BD0E-C1B9FF2AA3A0} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {F13108C4-4C86-4D56-A317-A4E5892A8AF7} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {F322ED35-A389-4B65-AC8A-E25F1337DBCC} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {F3E5650D-834E-45E6-90C7-3FC2AA954929} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {F5D850C9-D353-4B84-99BC-E336C231018C} = {BFEDF709-A700-4769-9056-ACA934D828A8} {F5E2F6C4-19BA-497A-B754-232E469BE647} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {F63FB47F-1DCE-48E5-9CBD-F3E0A354472B} = {E23BB160-006E-44F2-8FB4-3A2240BBC20C} {F7C6C6B6-4142-4C82-8699-4A9D8183181B} = {853D45D8-980C-4991-B62A-DAC6FD245402} {F8373EDD-1B9E-462D-BF23-55638E23E98B} = {746BA101-5C93-42A5-AC7A-64DCEB186572} {F8CCA5AE-2D75-4C79-BEAB-2588CD5956C8} = {853D45D8-980C-4991-B62A-DAC6FD245402} {FB2D2B18-E616-4639-8593-0E1AF2DA01A8} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} {FB6AFFAA-0279-41F7-A698-F81C90BBD987} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {FBB77433-639E-42DC-9355-EA94CAE294D2} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {FCD0587A-4504-4F5E-8E9C-468CC03D250A} = {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} {FD726AA3-D4FA-4597-B435-08CC7752888C} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {FD86DEA2-449E-44CD-A014-BFC30ED3FDF2} = {42F57B5A-9E6B-44DE-A6D3-7B03B3DFDED7} {FEA09B48-34C2-4963-8A5A-F97BDA136D72} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {FF374D62-CBCF-401E-9A02-1D3DB8BE16E4} = {45E74E38-35CA-4CB6-8965-BC20D39659AF} {FF6E5B0C-DC00-4C93-B9C2-63D1E858BA79} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5E690324-2D48-486A-8D3C-DCB520D3F693} EndGlobalSection EndGlobal pmdk-1.4.1/src/README000066400000000000000000000014241331545616200141260ustar00rootroot00000000000000Persistent Memory Development Kit This is src/README. This directory contains the source for the Persistent Memory Development Kit. libvmem is largely just a wrapper around a modified jemalloc library. See the "jemalloc" subdirectory and the git change log for those files for details. The subdirectory "include" contains header files that get delivered along with the libraries. Everything else is internal to the libraries and lives in this directory. Two versions of the libraries are built, a debug version and a nondebug version. The object files and the libraries themselves end up in the subdirectories "debug" and "nondebug". See the top-level README for build, test, and installation instructions. The basic "make" and "make test" targets also work from this directory. pmdk-1.4.1/src/benchmarks/000077500000000000000000000000001331545616200153625ustar00rootroot00000000000000pmdk-1.4.1/src/benchmarks/.gitignore000066400000000000000000000000331331545616200173460ustar00rootroot00000000000000pmembench *.csv testfile.* pmdk-1.4.1/src/benchmarks/Makefile000066400000000000000000000131441331545616200170250ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # src/benchmarks/Makefile -- build all benchmarks # TOP := $(dir $(lastword $(MAKEFILE_LIST)))../.. include $(TOP)/src/common.inc vpath %.c $(TOP)/src/examples/libpmemobj/tree_map vpath %.c $(TOP)/src/examples/libpmemobj/map vpath %.c $(TOP)/src/examples/libpmemobj/hashmap vpath %.c $(TOP)/src/libpmemobj vpath %.c $(TOP)/src/common vpath %.c $(TOP)/src/librpmem vpath %.c $(TOP)/src/rpmem_common BENCHMARK = pmembench GLIB:= $(call check_package, glib-2.0) ifeq ($(GLIB),y) TARGET = $(BENCHMARK) else $(info NOTE: Skipping pmembench because glib-2.0 is missing \ -- see src/benchmarks/README for details.) endif all: $(TARGET) SRC=pmembench.cpp\ benchmark_time.cpp\ benchmark_worker.cpp\ clo.cpp\ clo_vec.cpp\ config_reader.cpp\ scenario.cpp\ log.cpp\ blk.cpp\ vmem.cpp\ pmem_memset.cpp\ pmem_memcpy.cpp\ pmem_flush.cpp\ pmemobj_gen.cpp\ pmemobj_persist.cpp\ obj_pmalloc.cpp\ obj_locks.cpp\ obj_lanes.cpp\ map_bench.cpp\ pmemobj_tx.cpp\ pmemobj_atomic_lists.cpp # Configuration file without the .cfg extension CONFIGS=pmembench_log\ pmembench_blk\ pmembench_vmem\ pmembench_memset\ pmembench_memcpy\ pmembench_flush\ pmembench_obj_pmalloc\ pmembench_obj_persist\ pmembench_obj_gen\ pmembench_obj_locks\ pmembench_obj_lanes\ pmembench_map\ pmembench_tx\ pmembench_atomic_lists OBJS=$(SRC:.cpp=.o) ifneq ($(filter 1 2, $(CSTYLEON)),) TMP_HEADERS := $(addsuffix tmp, $(HEADERS)) endif LDFLAGS = -L$(LIBS_PATH) $(OS_LIBS) LDFLAGS += -L../examples/libpmemobj/map LDFLAGS += $(EXTRA_LDFLAGS) ifeq ($(DEBUG),) LIBS += ../nondebug/libpmemcommon.a else LIBS += ../debug/libpmemcommon.a endif LIBS += -lpmemobj -lpmemlog -lpmemblk -lpmem -lvmem -pthread -lm \ $(LIBDL) $(LIBUUID) ifeq ($(call check_librt), n) LIBS += -lrt endif CXXFLAGS = -Wall CXXFLAGS += -Werror CXXFLAGS += -std=c++0x CXXFLAGS += -Wno-invalid-offsetof CXXFLAGS += -Wpointer-arith CXXFLAGS += -Wunused-macros CXXFLAGS += -pthread CXXFLAGS += -I../include CXXFLAGS += -I../libpmemobj CXXFLAGS += -I../common CXXFLAGS += -I../examples/libpmemobj/map CXXFLAGS += -I../rpmem_common CXXFLAGS += -I../librpmem CXXFLAGS += $(OS_INCS) CXXFLAGS += -DSRCVERSION='"$(SRCVERSION)"' ifeq ($(COVERAGE),1) CXXFLAGS += $(GCOV_CFLAGS) LDFLAGS += $(GCOV_LDFLAGS) LIBS += $(GCOV_LIBS) endif ifneq ($(SANITIZE),) CXXFLAGS += -fsanitize=$(SANITIZE) LDFLAGS += -fsanitize=$(SANITIZE) endif ifeq ($(BUILD_RPMEM),y) SRC += rpmem_persist.cpp LIBS += -lrpmem $(shell pkg-config --libs libfabric) CONFIGS += pmembench_rpmem CXXFLAGS += -DRPMEM_AVAILABLE else $(info NOTE: Skipping librpmem benchmark because $(BUILD_RPMEM_INFO)) endif ifeq ($(GLIB),y) CXXFLAGS += $(shell $(PKG_CONFIG) --cflags glib-2.0) LIBS += $(shell $(PKG_CONFIG) --libs glib-2.0) endif LIBMAP_DIR=../examples/libpmemobj/map LIBMAP=$(LIBMAP_DIR)/libmap.a OBJS += pmemobj.o ifeq ($(DEBUG),) CXXFLAGS += -O3 LIBS_PATH=../nondebug else CXXFLAGS += -ggdb LIBS_PATH=../debug endif GLIB_TEST_PROG="\#include \nint main(){return 0;}" GLIB_SILENCE := $(shell printf $(GLIB_TEST_PROG) |\ $(CXX) $(CXXFLAGS) -x c -o /dev/null - 2>/dev/null && echo n || echo y) ifeq ($(GLIB_SILENCE), y) CXXFLAGS += -Wno-unknown-attributes endif CXXFLAGS += $(EXTRA_CXXFLAGS) objdir=. %.o: %.cpp Makefile $(call check-cstyle, $<) @mkdir -p .deps $(CXX) -MD -c -o $@ $(CXXFLAGS) $(call coverage-path, $<) $(call check-os, $@, $<) $(create-deps) %.htmp: %.h $(call check-cstyle, $<, $@) %.hpptmp: %.hpp $(call check-cstyle, $<, $@) $(BENCHMARK): $(TMP_HEADERS) $(OBJS) $(LIBMAP) $(CXX) -o $@ $(LDFLAGS) $(OBJS) $(LIBMAP) $(LIBS) $(LIBMAP): $(MAKE) -C $(LIBMAP_DIR) map clean: $(RM) $(OBJS) $(TMP_HEADERS) $(RM) *.csv clobber: clean $(RM) $(BENCHMARK) $(RM) *.csv $(RM) -r .deps $(CONFIGS): LD_LIBRARY_PATH=$(LIBS_PATH) ./$(BENCHMARK) $@.cfg > $@.csv run: $(BENCHMARK) $(CONFIGS) sparse: .PHONY: all clean clobber run $(CONFIGS) PMEMOBJ_SYMBOLS=pmalloc pfree lane_hold lane_release pmemobj.o: $(LIBS_PATH)/libpmemobj/libpmemobj_unscoped.o $(OBJCOPY) --localize-hidden $(addprefix -G, $(PMEMOBJ_SYMBOLS)) $< $@ -include .deps/*.P pmdk-1.4.1/src/benchmarks/README000066400000000000000000000010371331545616200162430ustar00rootroot00000000000000Persistent Memory Development Kit This is benchmarks/README. This directory contains benchmarks for Persistent Memory Development Kit. Benchmarks may be built and run from this directory using: $ make $ make run See how to run benchmarks manually using: $ LD_LIBRARY_PATH=../nondebug ./pmembench --help ** DEPENDENCIES: ** In order to build benchmarks you need to install glib-2.0 development package. rpm-based systems : glibX-devel (where X is the API/ABI version) dpkg-based systems: libglibX-dev (where X is the API/ABI version) pmdk-1.4.1/src/benchmarks/benchmark.hpp000066400000000000000000000261361331545616200200350ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * benchmark.hpp -- This file contains interface for creating benchmarks to the * pmembench framework. The _most_ important data structure is * struct benchmark_info which should be properly filled and registered by the * benchmark. Some fields should be filled by meta-data and information about * the benchmark like: name, brief description, supported operation modes etc. * The other group of fields are function callbacks which may be implemented by * the benchmark. Some callbacks are required, others are optional. This is * indicated in the structure description. * * To register a benchmark you can use the special macro * REGISTER_BENCHMARK() which takes static benchmark_info data structure as an * argument. You can also use the pmembench_register() function. Please note * that registering a benchmark should be done at initialization time. You can * achieve this by specifying pmembench_init macro in function attributes: * * static void pmembench_init my_benchmark_init() * { * pmembench_register(&my_benchmark); * } * * However using the REGISTER_BENCHMARK() macro is recommended. */ #ifndef _BENCHMARK_H #define _BENCHMARK_H #include #include #include #include #include #include #include "benchmark_time.hpp" #include "os.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif #define RRAND(max, min) (rand() % ((max) - (min)) + (min)) #define RRAND_R(seed, max, min) (os_rand_r(seed) % ((max) - (min)) + (min)) struct benchmark; /* * benchmark_args - Arguments for benchmark. * * It contains set of common arguments and pointer to benchmark's specific * arguments which are automatically processed by framework according to * clos, nclos and opt_size in benchmark_info structure. */ struct benchmark_args { const char *fname; /* path to test file */ size_t fsize; /* size of test file */ bool is_poolset; /* test file is a poolset */ mode_t fmode; /* test file's permissions */ unsigned n_threads; /* number of working threads */ size_t n_ops_per_thread; /* number of operations per thread */ bool thread_affinity; /* set worker threads CPU affinity mask */ ssize_t main_affinity; /* main thread affinity */ char *affinity_list; /* set CPU affinity order */ size_t dsize; /* data size */ unsigned seed; /* PRNG seed */ unsigned repeats; /* number of repeats of one scenario */ unsigned min_exe_time; /* minimal execution time */ bool help; /* print help for benchmark */ void *opts; /* benchmark specific arguments */ }; /* * benchmark_results - Benchmark's execution results. */ struct benchmark_results { uint64_t nbytes; /* number of bytes processed */ uint64_t nops; /* number of operations executed */ benchmark_time_t time; /* total execution time */ }; /* * Command Line Option integer value base. */ #define CLO_INT_BASE_NONE 0x0 #define CLO_INT_BASE_DEC 0x1 #define CLO_INT_BASE_HEX 0x2 #define CLO_INT_BASE_OCT 0x4 /* * Command Line Option type. */ enum clo_type { CLO_TYPE_FLAG, CLO_TYPE_STR, CLO_TYPE_INT, CLO_TYPE_UINT, CLO_TYPE_MAX, }; /* * Description of command line option. * * This structure is used to declare command line options by the benchmark * which will be automatically parsed by the framework. * * opt_short : Short option char. If there is no short option write 0. * opt_long : Long option string. * descr : Description of command line option. * off : Offset in data structure in which the value should be stored. * type : Type of command line option. * def : Default value. If set to NULL, this options is required. * ignore_in_res: Do not print in results. * check : Optional callback for checking the command line option value. * type_int : Parameters for signed integer. * type_uint : Parameters for unsigned integer. * type_str : Parameters for string. * * size : Size of integer value. Valid values: 1, 2, 4, 8. * base : Integer base system from which the parsing should be * performed. This field may be used as bit mask by logically * adding different base types. * limit_min : Indicates whether value should be limited by the minimum * value. * limit_max : Indicates whether value should be limited by the maximum * value. * min : Minimum value when limit_min is set. * max : Maximum value when limit_min is set. * * alloc : If set to true the framework should allocate memory for the * value. The memory will be freed by the framework at the end of * execution. Otherwise benchmark must provide valid pointer in * opt_var and max_size parameter must be set properly. * max_size : Maximum size of string. */ struct benchmark_clo { int opt_short; const char *opt_long; enum clo_type type; const char *descr; size_t off; const char *def; bool ignore_in_res; struct { size_t size; int base; int64_t min; int64_t max; } type_int; struct { size_t size; int base; uint64_t min; uint64_t max; } type_uint; int used; }; #define clo_field_offset(s, f) ((size_t) & ((s *)0)->f) #define clo_field_size(s, f) (sizeof(((s *)0)->f)) /* * worker_info - Worker thread's information structure. */ struct worker_info { size_t index; /* index of worker thread */ struct operation_info *opinfo; /* operation info structure */ size_t nops; /* number of operations */ void *priv; /* worker's private data */ benchmark_time_t beg; /* start time */ benchmark_time_t end; /* end time */ }; /* * operation_info - Information about operation. */ struct operation_info { struct worker_info *worker; /* worker's info */ struct benchmark_args *args; /* benchmark arguments */ size_t index; /* operation's index */ benchmark_time_t end; /* operation's end time */ }; /* * struct benchmark_info -- benchmark descriptor * name : Name of benchmark. * brief : Brief description of benchmark. * clos : Command line options which will be automatically parsed by * framework. * nclos : Number of command line options. * opts_size : Size of data structure where the parsed values should be * stored in. * print_help : Callback for printing help message. * pre_init : Function for initialization of the benchmark before parsing * command line arguments. * init : Function for initialization of the benchmark after parsing * command line arguments. * exit : Function for de-initialization of the benchmark. * multithread : Indicates whether the benchmark operation function may be * run in many threads. * multiops : Indicates whether the benchmark operation function may be * run many time in a loop. * measure_time : Indicates whether the benchmark framework should measure the * execution time of operation function. If set to false, the * benchmark must report the execution time by itself. * init_worker : Callback for initialization thread specific data. Invoked in * a single thread for every thread worker. * operation : Callback function which does the main job of benchmark. * rm_file : Indicates whether the test file should be removed by * framework before the init function will be called. * allow_poolset: Indicates whether benchmark may use poolset files. * If set to false and fname points to a poolset, an error * will be returned. * According to multithread and single_operation flags it may be * invoked in different ways: * +-------------+----------+-------------------------------------+ * | multithread | multiops | description | * +-------------+----------+-------------------------------------+ * | false | false | invoked once, in one thread | * +-------------+----------+-------------------------------------+ * | false | true | invoked many times, in one thread | * +-------------+----------+-------------------------------------+ * | true | false | invoked once, in many threads | * +-------------+----------+-------------------------------------+ * | true | true | invoked many times, in many threads | * +-------------+----------+-------------------------------------+ * */ struct benchmark_info { const char *name; const char *brief; struct benchmark_clo *clos; size_t nclos; size_t opts_size; void (*print_help)(struct benchmark *bench); int (*pre_init)(struct benchmark *bench); int (*init)(struct benchmark *bench, struct benchmark_args *args); int (*exit)(struct benchmark *bench, struct benchmark_args *args); int (*init_worker)(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker); void (*free_worker)(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker); int (*operation)(struct benchmark *bench, struct operation_info *info); bool multithread; bool multiops; bool measure_time; bool rm_file; bool allow_poolset; }; void *pmembench_get_priv(struct benchmark *bench); void pmembench_set_priv(struct benchmark *bench, void *priv); struct benchmark_info *pmembench_get_info(struct benchmark *bench); int pmembench_register(struct benchmark_info *bench_info); #define REGISTER_BENCHMARK(bench) \ if (pmembench_register(&bench)) { \ fprintf(stderr, "Unable to register benchmark '%s'\n", \ bench.name); \ } #endif /* _BENCHMARK_H */ pmdk-1.4.1/src/benchmarks/benchmark_time.cpp000066400000000000000000000075261331545616200210500ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * benchmark_time.cpp -- benchmark_time module definitions */ #include "benchmark_time.hpp" #include "os.h" #include #include #include #include #define NSECPSEC 1000000000 /* * benchmark_time_get -- get timestamp from clock source */ void benchmark_time_get(benchmark_time_t *time) { os_clock_gettime(CLOCK_MONOTONIC, time); } /* * benchmark_time_diff -- get time interval */ void benchmark_time_diff(benchmark_time_t *d, benchmark_time_t *t1, benchmark_time_t *t2) { long long nsecs = (t2->tv_sec - t1->tv_sec) * NSECPSEC + t2->tv_nsec - t1->tv_nsec; assert(nsecs >= 0); d->tv_sec = nsecs / NSECPSEC; d->tv_nsec = nsecs % NSECPSEC; } /* * benchmark_time_get_secs -- get total number of seconds */ double benchmark_time_get_secs(benchmark_time_t *t) { return (double)t->tv_sec + (double)t->tv_nsec / NSECPSEC; } /* * benchmark_time_get_nsecs -- get total number of nanoseconds */ unsigned long long benchmark_time_get_nsecs(benchmark_time_t *t) { unsigned long long ret = t->tv_nsec; ret += t->tv_sec * NSECPSEC; return ret; } /* * benchmark_time_compare -- compare two moments in time */ int benchmark_time_compare(const benchmark_time_t *t1, const benchmark_time_t *t2) { if (t1->tv_sec == t2->tv_sec) return (int)((long long)t1->tv_nsec - (long long)t2->tv_nsec); else return (int)((long long)t1->tv_sec - (long long)t2->tv_sec); } /* * benchmark_time_set -- set time using number of nanoseconds */ void benchmark_time_set(benchmark_time_t *time, unsigned long long nsecs) { time->tv_sec = nsecs / NSECPSEC; time->tv_nsec = nsecs % NSECPSEC; } /* * number of samples used to calculate average time required to get a current * time from the system */ #define N_PROBES_GET_TIME 10000000UL /* * benchmark_get_avg_get_time -- calculates average time required to get the * current time from the system in nanoseconds */ unsigned long long benchmark_get_avg_get_time(void) { benchmark_time_t time; benchmark_time_t start; benchmark_time_t stop; benchmark_time_get(&start); for (size_t i = 0; i < N_PROBES_GET_TIME; i++) { benchmark_time_get(&time); } benchmark_time_get(&stop); benchmark_time_diff(&time, &start, &stop); unsigned long long avg = benchmark_time_get_nsecs(&time) / N_PROBES_GET_TIME; return avg; } pmdk-1.4.1/src/benchmarks/benchmark_time.hpp000066400000000000000000000042451331545616200210500ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * benchmark_time.hpp -- declarations of benchmark_time module */ #include typedef struct timespec benchmark_time_t; void benchmark_time_get(benchmark_time_t *time); void benchmark_time_diff(benchmark_time_t *d, benchmark_time_t *t1, benchmark_time_t *t2); double benchmark_time_get_secs(benchmark_time_t *t); unsigned long long benchmark_time_get_nsecs(benchmark_time_t *t); int benchmark_time_compare(const benchmark_time_t *t1, const benchmark_time_t *t2); void benchmark_time_set(benchmark_time_t *time, unsigned long long nsecs); unsigned long long benchmark_get_avg_get_time(void); pmdk-1.4.1/src/benchmarks/benchmark_worker.cpp000066400000000000000000000127761331545616200214260ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * benchmark_worker.cpp -- benchmark_worker module definitions */ #include #include #include "benchmark_worker.hpp" #include "os_thread.h" /* * worker_state_wait_for_transition -- wait for transition from and to * specified states */ static void worker_state_wait_for_transition(struct benchmark_worker *worker, enum benchmark_worker_state state, enum benchmark_worker_state new_state) { while (worker->state == state) os_cond_wait(&worker->cond, &worker->lock); assert(worker->state == new_state); } /* * worker_state_transition -- change worker state from and to specified states */ static void worker_state_transition(struct benchmark_worker *worker, enum benchmark_worker_state old_state, enum benchmark_worker_state new_state) { assert(worker->state == old_state); worker->state = new_state; os_cond_signal(&worker->cond); } /* * thread_func -- (internal) callback for os_thread */ static void * thread_func(void *arg) { assert(arg != NULL); struct benchmark_worker *worker = (struct benchmark_worker *)arg; os_mutex_lock(&worker->lock); worker_state_wait_for_transition(worker, WORKER_STATE_IDLE, WORKER_STATE_INIT); if (worker->init) worker->ret_init = worker->init(worker->bench, worker->args, &worker->info); worker_state_transition(worker, WORKER_STATE_INIT, WORKER_STATE_INITIALIZED); worker_state_wait_for_transition(worker, WORKER_STATE_INITIALIZED, WORKER_STATE_RUN); worker->ret = worker->func(worker->bench, &worker->info); worker_state_transition(worker, WORKER_STATE_RUN, WORKER_STATE_END); worker_state_wait_for_transition(worker, WORKER_STATE_END, WORKER_STATE_EXIT); if (worker->exit) worker->exit(worker->bench, worker->args, &worker->info); worker_state_transition(worker, WORKER_STATE_EXIT, WORKER_STATE_DONE); os_mutex_unlock(&worker->lock); return NULL; } /* * benchmark_worker_alloc -- allocate benchmark worker */ struct benchmark_worker * benchmark_worker_alloc(void) { struct benchmark_worker *w = (struct benchmark_worker *)calloc(1, sizeof(*w)); if (!w) return NULL; if (os_mutex_init(&w->lock)) goto err_free_worker; if (os_cond_init(&w->cond)) goto err_destroy_mutex; if (os_thread_create(&w->thread, NULL, thread_func, w)) goto err_destroy_cond; return w; err_destroy_cond: os_cond_destroy(&w->cond); err_destroy_mutex: os_mutex_destroy(&w->lock); err_free_worker: free(w); return NULL; } /* * benchmark_worker_free -- release benchmark worker */ void benchmark_worker_free(struct benchmark_worker *w) { os_thread_join(&w->thread, NULL); os_cond_destroy(&w->cond); os_mutex_destroy(&w->lock); free(w); } /* * benchmark_worker_init -- call init function for worker */ int benchmark_worker_init(struct benchmark_worker *worker) { os_mutex_lock(&worker->lock); worker_state_transition(worker, WORKER_STATE_IDLE, WORKER_STATE_INIT); worker_state_wait_for_transition(worker, WORKER_STATE_INIT, WORKER_STATE_INITIALIZED); int ret = worker->ret_init; os_mutex_unlock(&worker->lock); return ret; } /* * benchmark_worker_exit -- call exit function for worker */ void benchmark_worker_exit(struct benchmark_worker *worker) { os_mutex_lock(&worker->lock); worker_state_transition(worker, WORKER_STATE_END, WORKER_STATE_EXIT); worker_state_wait_for_transition(worker, WORKER_STATE_EXIT, WORKER_STATE_DONE); os_mutex_unlock(&worker->lock); } /* * benchmark_worker_run -- run benchmark worker */ int benchmark_worker_run(struct benchmark_worker *worker) { int ret = 0; os_mutex_lock(&worker->lock); worker_state_transition(worker, WORKER_STATE_INITIALIZED, WORKER_STATE_RUN); os_mutex_unlock(&worker->lock); return ret; } /* * benchmark_worker_join -- join benchmark worker */ int benchmark_worker_join(struct benchmark_worker *worker) { os_mutex_lock(&worker->lock); worker_state_wait_for_transition(worker, WORKER_STATE_RUN, WORKER_STATE_END); os_mutex_unlock(&worker->lock); return 0; } pmdk-1.4.1/src/benchmarks/benchmark_worker.hpp000066400000000000000000000077731331545616200214340ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * benchmark_worker.hpp -- benchmark_worker module declarations */ #include "benchmark.hpp" #include "os_thread.h" /* * * The following table shows valid state transitions upon specified * API calls and operations performed by the worker thread: * * +========================+==========================+=============+ * | Application | State | Worker | * +========================+==========================+=============+ * | benchmark_worker_alloc | WORKER_STATE_IDLE | wait | * +------------------------+--------------------------+-------------+ * | benchmark_worker_init | WORKER_STATE_INIT | invoke init | * +------------------------+--------------------------+-------------+ * | wait | WORKER_STATE_INITIALIZED | end of init | * +------------------------+--------------------------+-------------+ * | benchmark_worker_run | WORKER_STATE_RUN | invoke func | * +------------------------+--------------------------+-------------+ * | benchmark_worker_join | WORKER_STATE_END | end of func | * +------------------------+--------------------------+-------------+ * | benchmark_worker_exit | WORKER_STATE_EXIT | invoke exit | * +------------------------+--------------------------+-------------+ * | wait | WORKER_STATE_DONE | end of exit | * +------------------------+--------------------------+-------------+ */ enum benchmark_worker_state { WORKER_STATE_IDLE, WORKER_STATE_INIT, WORKER_STATE_INITIALIZED, WORKER_STATE_RUN, WORKER_STATE_END, WORKER_STATE_EXIT, WORKER_STATE_DONE, MAX_WORKER_STATE, }; struct benchmark_worker { os_thread_t thread; struct benchmark *bench; struct benchmark_args *args; struct worker_info info; int ret; int ret_init; int (*func)(struct benchmark *bench, struct worker_info *info); int (*init)(struct benchmark *bench, struct benchmark_args *args, struct worker_info *info); void (*exit)(struct benchmark *bench, struct benchmark_args *args, struct worker_info *info); os_cond_t cond; os_mutex_t lock; enum benchmark_worker_state state; }; struct benchmark_worker *benchmark_worker_alloc(void); void benchmark_worker_free(struct benchmark_worker *); int benchmark_worker_init(struct benchmark_worker *); void benchmark_worker_exit(struct benchmark_worker *); int benchmark_worker_run(struct benchmark_worker *); int benchmark_worker_join(struct benchmark_worker *); pmdk-1.4.1/src/benchmarks/blk.cpp000066400000000000000000000401121331545616200166340ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * blk.cpp -- pmemblk benchmarks definitions */ #include "benchmark.hpp" #include "libpmem.h" #include "libpmemblk.h" #include "os.h" #include #include #include #include #include #include #include #include struct blk_bench; struct blk_worker; /* * op_type -- type of operation */ enum op_type { OP_TYPE_UNKNOWN, OP_TYPE_BLK, OP_TYPE_FILE, OP_TYPE_MEMCPY, }; /* * op_mode -- mode of the copy process */ enum op_mode { OP_MODE_UNKNOWN, OP_MODE_STAT, /* read/write always the same chunk */ OP_MODE_SEQ, /* read/write chunk by chunk */ OP_MODE_RAND /* read/write to chunks selected randomly */ }; /* * typedef for the worker function */ typedef int (*worker_fn)(struct blk_bench *, struct benchmark_args *, struct blk_worker *, os_off_t); /* * blk_args -- benchmark specific arguments */ struct blk_args { size_t fsize; /* requested file size */ bool no_warmup; /* don't do warmup */ unsigned seed; /* seed for randomization */ char *type_str; /* type: blk, file, memcpy */ char *mode_str; /* mode: stat, seq, rand */ }; /* * blk_bench -- pmemblk benchmark context */ struct blk_bench { PMEMblkpool *pbp; /* pmemblk handle */ char *addr; /* address of user data (memcpy) */ int fd; /* file descr. for file io */ size_t nblocks; /* actual number of blocks */ size_t blocks_per_thread; /* number of blocks per thread */ worker_fn worker; /* worker function */ enum op_type type; enum op_mode mode; }; /* * struct blk_worker -- pmemblk worker context */ struct blk_worker { os_off_t *blocks; /* array with block numbers */ char *buff; /* buffer for read/write */ unsigned seed; /* worker seed */ }; /* * parse_op_type -- parse command line "--operation" argument * * Returns proper operation type. */ static enum op_type parse_op_type(const char *arg) { if (strcmp(arg, "blk") == 0) return OP_TYPE_BLK; else if (strcmp(arg, "file") == 0) return OP_TYPE_FILE; else if (strcmp(arg, "memcpy") == 0) return OP_TYPE_MEMCPY; else return OP_TYPE_UNKNOWN; } /* * parse_op_mode -- parse command line "--mode" argument * * Returns proper operation mode. */ static enum op_mode parse_op_mode(const char *arg) { if (strcmp(arg, "stat") == 0) return OP_MODE_STAT; else if (strcmp(arg, "seq") == 0) return OP_MODE_SEQ; else if (strcmp(arg, "rand") == 0) return OP_MODE_RAND; else return OP_MODE_UNKNOWN; } /* * blk_do_warmup -- perform warm-up by writing to each block */ static int blk_do_warmup(struct blk_bench *bb, struct benchmark_args *args) { size_t lba; int ret = 0; char *buff = (char *)calloc(1, args->dsize); if (!buff) { perror("calloc"); return -1; } for (lba = 0; lba < bb->nblocks; ++lba) { switch (bb->type) { case OP_TYPE_FILE: { size_t off = lba * args->dsize; if (pwrite(bb->fd, buff, args->dsize, off) != (ssize_t)args->dsize) { perror("pwrite"); ret = -1; goto out; } } break; case OP_TYPE_BLK: if (pmemblk_write(bb->pbp, buff, lba) < 0) { perror("pmemblk_write"); ret = -1; goto out; } break; case OP_TYPE_MEMCPY: { size_t off = lba * args->dsize; pmem_memcpy_persist((char *)bb->addr + off, buff, args->dsize); } break; default: perror("unknown type"); ret = -1; goto out; } } out: free(buff); return ret; } /* * blk_read -- read function for pmemblk */ static int blk_read(struct blk_bench *bb, struct benchmark_args *ba, struct blk_worker *bworker, os_off_t off) { if (pmemblk_read(bb->pbp, bworker->buff, off) < 0) { perror("pmemblk_read"); return -1; } return 0; } /* * fileio_read -- read function for file io */ static int fileio_read(struct blk_bench *bb, struct benchmark_args *ba, struct blk_worker *bworker, os_off_t off) { os_off_t file_off = off * ba->dsize; if (pread(bb->fd, bworker->buff, ba->dsize, file_off) != (ssize_t)ba->dsize) { perror("pread"); return -1; } return 0; } /* * memcpy_read -- read function for memcpy */ static int memcpy_read(struct blk_bench *bb, struct benchmark_args *ba, struct blk_worker *bworker, os_off_t off) { os_off_t file_off = off * ba->dsize; memcpy(bworker->buff, (char *)bb->addr + file_off, ba->dsize); return 0; } /* * blk_write -- write function for pmemblk */ static int blk_write(struct blk_bench *bb, struct benchmark_args *ba, struct blk_worker *bworker, os_off_t off) { if (pmemblk_write(bb->pbp, bworker->buff, off) < 0) { perror("pmemblk_write"); return -1; } return 0; } /* * memcpy_write -- write function for memcpy */ static int memcpy_write(struct blk_bench *bb, struct benchmark_args *ba, struct blk_worker *bworker, os_off_t off) { os_off_t file_off = off * ba->dsize; pmem_memcpy_persist((char *)bb->addr + file_off, bworker->buff, ba->dsize); return 0; } /* * fileio_write -- write function for file io */ static int fileio_write(struct blk_bench *bb, struct benchmark_args *ba, struct blk_worker *bworker, os_off_t off) { os_off_t file_off = off * ba->dsize; if (pwrite(bb->fd, bworker->buff, ba->dsize, file_off) != (ssize_t)ba->dsize) { perror("pwrite"); return -1; } return 0; } /* * blk_operation -- main operations for blk_read and blk_write benchmark */ static int blk_operation(struct benchmark *bench, struct operation_info *info) { struct blk_bench *bb = (struct blk_bench *)pmembench_get_priv(bench); struct blk_worker *bworker = (struct blk_worker *)info->worker->priv; os_off_t off = bworker->blocks[info->index]; return bb->worker(bb, info->args, bworker, off); } /* * blk_init_worker -- initialize worker */ static int blk_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct blk_worker *bworker = (struct blk_worker *)malloc(sizeof(*bworker)); if (!bworker) { perror("malloc"); return -1; } struct blk_bench *bb = (struct blk_bench *)pmembench_get_priv(bench); struct blk_args *bargs = (struct blk_args *)args->opts; bworker->seed = os_rand_r(&bargs->seed); bworker->buff = (char *)malloc(args->dsize); if (!bworker->buff) { perror("malloc"); goto err_buff; } /* fill buffer with some random data */ memset(bworker->buff, bworker->seed, args->dsize); assert(args->n_ops_per_thread != 0); bworker->blocks = (os_off_t *)malloc(sizeof(*bworker->blocks) * args->n_ops_per_thread); if (!bworker->blocks) { perror("malloc"); goto err_blocks; } switch (bb->mode) { case OP_MODE_RAND: for (size_t i = 0; i < args->n_ops_per_thread; i++) { bworker->blocks[i] = worker->index * bb->blocks_per_thread + os_rand_r(&bworker->seed) % bb->blocks_per_thread; } break; case OP_MODE_SEQ: for (size_t i = 0; i < args->n_ops_per_thread; i++) bworker->blocks[i] = i % bb->blocks_per_thread; break; case OP_MODE_STAT: for (size_t i = 0; i < args->n_ops_per_thread; i++) bworker->blocks[i] = 0; break; default: perror("unknown mode"); goto err_blocks; } worker->priv = bworker; return 0; err_blocks: free(bworker->buff); err_buff: free(bworker); return -1; } /* * blk_free_worker -- cleanup worker */ static void blk_free_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct blk_worker *bworker = (struct blk_worker *)worker->priv; free(bworker->blocks); free(bworker->buff); free(bworker); } /* * blk_init -- function for initialization benchmark */ static int blk_init(struct blk_bench *bb, struct benchmark_args *args) { struct blk_args *ba = (struct blk_args *)args->opts; assert(ba != NULL); bb->type = parse_op_type(ba->type_str); if (bb->type == OP_TYPE_UNKNOWN) { fprintf(stderr, "Invalid operation argument '%s'", ba->type_str); return -1; } bb->mode = parse_op_mode(ba->mode_str); if (bb->mode == OP_MODE_UNKNOWN) { fprintf(stderr, "Invalid mode argument '%s'", ba->mode_str); return -1; } if (ba->fsize == 0) ba->fsize = PMEMBLK_MIN_POOL; size_t req_fsize = ba->fsize; if (ba->fsize / args->dsize < args->n_threads || ba->fsize < PMEMBLK_MIN_POOL) { fprintf(stderr, "too small file size\n"); return -1; } if (args->dsize >= ba->fsize) { fprintf(stderr, "block size bigger than file size\n"); return -1; } if (args->is_poolset) { if (args->fsize < ba->fsize) { fprintf(stderr, "insufficient size of poolset\n"); return -1; } ba->fsize = 0; } bb->fd = -1; /* * Create pmemblk in order to get the number of blocks * even for file-io mode. */ bb->pbp = pmemblk_create(args->fname, args->dsize, ba->fsize, args->fmode); if (bb->pbp == NULL) { perror("pmemblk_create"); return -1; } bb->nblocks = pmemblk_nblock(bb->pbp); /* limit the number of used blocks */ if (bb->nblocks > req_fsize / args->dsize) bb->nblocks = req_fsize / args->dsize; if (bb->nblocks < args->n_threads) { fprintf(stderr, "too small file size"); goto out_close; } if (bb->type == OP_TYPE_FILE) { pmemblk_close(bb->pbp); bb->pbp = NULL; int flags = O_RDWR | O_CREAT | O_SYNC; #ifdef _WIN32 flags |= O_BINARY; #endif bb->fd = os_open(args->fname, flags, args->fmode); if (bb->fd < 0) { perror("open"); return -1; } } else if (bb->type == OP_TYPE_MEMCPY) { /* skip pool header, so addr points to the first block */ bb->addr = (char *)bb->pbp + 8192; } bb->blocks_per_thread = bb->nblocks / args->n_threads; if (!ba->no_warmup) { if (blk_do_warmup(bb, args) != 0) goto out_close; } return 0; out_close: if (bb->type == OP_TYPE_FILE) os_close(bb->fd); else pmemblk_close(bb->pbp); return -1; } /* * blk_read_init - function for initializing blk_read benchmark */ static int blk_read_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); int ret; struct blk_bench *bb = (struct blk_bench *)malloc(sizeof(struct blk_bench)); if (bb == NULL) { perror("malloc"); return -1; } pmembench_set_priv(bench, bb); ret = blk_init(bb, args); if (ret != 0) { free(bb); return ret; } switch (bb->type) { case OP_TYPE_FILE: bb->worker = fileio_read; break; case OP_TYPE_BLK: bb->worker = blk_read; break; case OP_TYPE_MEMCPY: bb->worker = memcpy_read; break; default: perror("unknown operation type"); return -1; } return ret; } /* * blk_write_init - function for initializing blk_write benchmark */ static int blk_write_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); int ret; struct blk_bench *bb = (struct blk_bench *)malloc(sizeof(struct blk_bench)); if (bb == NULL) { perror("malloc"); return -1; } pmembench_set_priv(bench, bb); ret = blk_init(bb, args); if (ret != 0) { free(bb); return ret; } switch (bb->type) { case OP_TYPE_FILE: bb->worker = fileio_write; break; case OP_TYPE_BLK: bb->worker = blk_write; break; case OP_TYPE_MEMCPY: bb->worker = memcpy_write; break; default: perror("unknown operation type"); return -1; } return ret; } /* * blk_exit -- function for de-initialization benchmark */ static int blk_exit(struct benchmark *bench, struct benchmark_args *args) { struct blk_bench *bb = (struct blk_bench *)pmembench_get_priv(bench); int result; switch (bb->type) { case OP_TYPE_FILE: os_close(bb->fd); break; case OP_TYPE_BLK: pmemblk_close(bb->pbp); result = pmemblk_check(args->fname, args->dsize); if (result < 0) { perror("pmemblk_check error"); return -1; } else if (result == 0) { perror("pmemblk_check: not consistent"); return -1; } break; case OP_TYPE_MEMCPY: pmemblk_close(bb->pbp); break; default: perror("unknown operation type"); return -1; } free(bb); return 0; } static struct benchmark_clo blk_clo[5]; static struct benchmark_info blk_read_info; static struct benchmark_info blk_write_info; CONSTRUCTOR(blk_costructor) void blk_costructor(void) { blk_clo[0].opt_short = 'o'; blk_clo[0].opt_long = "operation"; blk_clo[0].descr = "Operation type - blk, file, memcpy"; blk_clo[0].type = CLO_TYPE_STR; blk_clo[0].off = clo_field_offset(struct blk_args, type_str); blk_clo[0].def = "blk"; blk_clo[1].opt_short = 'w'; blk_clo[1].opt_long = "no-warmup"; blk_clo[1].descr = "Don't do warmup"; blk_clo[1].type = CLO_TYPE_FLAG; blk_clo[1].off = clo_field_offset(struct blk_args, no_warmup); blk_clo[2].opt_short = 'm'; blk_clo[2].opt_long = "mode"; blk_clo[2].descr = "Reading/writing mode - stat, seq, rand"; blk_clo[2].type = CLO_TYPE_STR; blk_clo[2].off = clo_field_offset(struct blk_args, mode_str); blk_clo[2].def = "seq"; blk_clo[3].opt_short = 'S'; blk_clo[3].opt_long = "seed"; blk_clo[3].descr = "Random seed"; blk_clo[3].off = clo_field_offset(struct blk_args, seed); blk_clo[3].def = "1"; blk_clo[3].type = CLO_TYPE_UINT; blk_clo[3].type_uint.size = clo_field_size(struct blk_args, seed); blk_clo[3].type_uint.base = CLO_INT_BASE_DEC; blk_clo[3].type_uint.min = 1; blk_clo[3].type_uint.max = UINT_MAX; blk_clo[4].opt_short = 's'; blk_clo[4].opt_long = "file-size"; blk_clo[4].descr = "Requested file size in bytes - 0 means minimum"; blk_clo[4].type = CLO_TYPE_UINT; blk_clo[4].off = clo_field_offset(struct blk_args, fsize); blk_clo[4].def = "0"; blk_clo[4].type_uint.size = clo_field_size(struct blk_args, fsize); blk_clo[4].type_uint.base = CLO_INT_BASE_DEC; blk_clo[4].type_uint.min = 0; blk_clo[4].type_uint.max = ~0; blk_read_info.name = "blk_read"; blk_read_info.brief = "Benchmark for blk_read() operation"; blk_read_info.init = blk_read_init; blk_read_info.exit = blk_exit; blk_read_info.multithread = true; blk_read_info.multiops = true; blk_read_info.init_worker = blk_init_worker; blk_read_info.free_worker = blk_free_worker; blk_read_info.operation = blk_operation; blk_read_info.clos = blk_clo; blk_read_info.nclos = ARRAY_SIZE(blk_clo); blk_read_info.opts_size = sizeof(struct blk_args); blk_read_info.rm_file = true; blk_read_info.allow_poolset = true; REGISTER_BENCHMARK(blk_read_info); blk_write_info.name = "blk_write"; blk_write_info.brief = "Benchmark for blk_write() operation"; blk_write_info.init = blk_write_init; blk_write_info.exit = blk_exit; blk_write_info.multithread = true; blk_write_info.multiops = true; blk_write_info.init_worker = blk_init_worker; blk_write_info.free_worker = blk_free_worker; blk_write_info.operation = blk_operation; blk_write_info.clos = blk_clo; blk_write_info.nclos = ARRAY_SIZE(blk_clo); blk_write_info.opts_size = sizeof(struct blk_args); blk_write_info.rm_file = true; blk_write_info.allow_poolset = true; REGISTER_BENCHMARK(blk_write_info); } pmdk-1.4.1/src/benchmarks/clo.cpp000066400000000000000000000577111331545616200166560ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * clo.cpp -- command line options module definitions */ #include #include #include #include #include #include #include "benchmark.hpp" #include "clo.hpp" #include "clo_vec.hpp" #include "queue.h" #include "scenario.hpp" #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) #endif typedef int (*clo_parse_fn)(struct benchmark_clo *clo, const char *arg, struct clo_vec *clovec); typedef int (*clo_parse_single_fn)(struct benchmark_clo *clo, const char *arg, void *ptr); typedef int (*clo_eval_range_fn)(struct benchmark_clo *clo, void *first, void *step, void *last, char type, struct clo_vec_vlist *vlist); typedef const char *(*clo_str_fn)(struct benchmark_clo *clo, void *addr, size_t size); #define STR_BUFF_SIZE 1024 static char str_buff[STR_BUFF_SIZE]; /* * clo_parse_flag -- (internal) parse flag */ static int clo_parse_flag(struct benchmark_clo *clo, const char *arg, struct clo_vec *clovec) { bool flag = true; if (arg != NULL) { if (strcmp(arg, "true") == 0) flag = true; else if (strcmp(arg, "false") == 0) flag = false; else return -1; } return clo_vec_memcpy(clovec, clo->off, sizeof(flag), &flag); } /* * clo_parse_str -- (internal) parse string value */ static int clo_parse_str(struct benchmark_clo *clo, const char *arg, struct clo_vec *clovec) { struct clo_vec_vlist *vlist = clo_vec_vlist_alloc(); assert(vlist != NULL); char *str = strdup(arg); assert(str != NULL); clo_vec_add_alloc(clovec, str); char *next = strtok(str, ","); while (next) { clo_vec_vlist_add(vlist, &next, sizeof(next)); next = strtok(NULL, ","); } int ret = clo_vec_memcpy_list(clovec, clo->off, sizeof(str), vlist); clo_vec_vlist_free(vlist); return ret; } /* * is_oct -- check if string may be octal number */ static int is_oct(const char *arg, size_t len) { return (arg[0] == '0' || (len > 1 && arg[0] == '-' && arg[1] == '0')); } /* * is_hex -- check if string may be hexadecimal number */ static int is_hex(const char *arg, size_t len) { if (arg[0] == '-') { arg++; len--; } return (len > 2 && arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')); } /* * parse_number_base -- parse string as integer of given sign and base */ static int parse_number_base(const char *arg, void *value, int s, int base) { char *end; errno = 0; if (s) { int64_t *v = (int64_t *)value; *v = strtoll(arg, &end, base); } else { uint64_t *v = (uint64_t *)value; *v = strtoull(arg, &end, base); } if (errno || *end != '\0') return -1; return 0; } /* * parse_number -- parse string as integer of given sign and allowed bases */ static int parse_number(const char *arg, size_t len, void *value, int s, int base) { if ((base & CLO_INT_BASE_HEX) && is_hex(arg, len)) { if (!parse_number_base(arg, value, s, 16)) return 0; } if ((base & CLO_INT_BASE_OCT) && is_oct(arg, len)) { if (!parse_number_base(arg, value, s, 8)) return 0; } if (base & CLO_INT_BASE_DEC) { if (!parse_number_base(arg, value, s, 10)) return 0; } return -1; } /* * clo_parse_single_int -- (internal) parse single int value */ static int clo_parse_single_int(struct benchmark_clo *clo, const char *arg, void *ptr) { int64_t value = 0; size_t len = strlen(arg); if (parse_number(arg, len, &value, 1, clo->type_int.base)) { errno = EINVAL; return -1; } int64_t tmax = ((int64_t)1 << (8 * clo->type_int.size - 1)) - 1; int64_t tmin = -((int64_t)1 << (8 * clo->type_int.size - 1)); tmax = min(tmax, clo->type_int.max); tmin = max(tmin, clo->type_int.min); if (value > tmax || value < tmin) { errno = ERANGE; return -1; } memcpy(ptr, &value, clo->type_int.size); return 0; } /* * clo_parse_single_uint -- (internal) parse single uint value */ static int clo_parse_single_uint(struct benchmark_clo *clo, const char *arg, void *ptr) { if (arg[0] == '-') { errno = EINVAL; return -1; } uint64_t value = 0; size_t len = strlen(arg); if (parse_number(arg, len, &value, 0, clo->type_uint.base)) { errno = EINVAL; return -1; } uint64_t tmax = ~0 >> (64 - 8 * clo->type_uint.size); uint64_t tmin = 0; tmax = min(tmax, clo->type_uint.max); tmin = max(tmin, clo->type_uint.min); if (value > tmax || value < tmin) { errno = ERANGE; return -1; } memcpy(ptr, &value, clo->type_uint.size); return 0; } /* * clo_eval_range_uint -- (internal) evaluate range for uint values */ static int clo_eval_range_uint(struct benchmark_clo *clo, void *first, void *step, void *last, char type, struct clo_vec_vlist *vlist) { uint64_t curr = *(uint64_t *)first; uint64_t l = *(uint64_t *)last; int64_t s = *(int64_t *)step; while (1) { clo_vec_vlist_add(vlist, &curr, clo->type_uint.size); switch (type) { case '+': curr += s; if (curr > l) return 0; break; case '-': if (curr < (uint64_t)s) return 0; curr -= s; if (curr < l) return 0; break; case '*': curr *= s; if (curr > l) return 0; break; case '/': curr /= s; if (curr < l) return 0; break; default: return -1; } } return -1; } /* * clo_eval_range_int -- (internal) evaluate range for int values */ static int clo_eval_range_int(struct benchmark_clo *clo, void *first, void *step, void *last, char type, struct clo_vec_vlist *vlist) { int64_t curr = *(int64_t *)first; int64_t l = *(int64_t *)last; uint64_t s = *(uint64_t *)step; while (1) { clo_vec_vlist_add(vlist, &curr, clo->type_int.size); switch (type) { case '+': curr += s; if (curr > l) return 0; break; case '-': curr -= s; if (curr < l) return 0; break; case '*': curr *= s; if (curr > l) return 0; break; case '/': curr /= s; if (curr < l) return 0; break; default: return -1; } } return -1; } /* * clo_check_range_params -- (internal) validate step and step type */ static int clo_check_range_params(uint64_t step, char step_type) { switch (step_type) { /* * Cannot construct range with step equal to 0 * for '+' or '-' range. */ case '+': case '-': if (step == 0) return -1; break; /* * Cannot construct range with step equal to 0 or 1 * for '*' or '/' range. */ case '*': case '/': if (step == 0 || step == 1) return -1; break; default: return -1; } return 0; } /* * clo_parse_range -- (internal) parse range or value * * The range may be in the following format: * :: * * Step type must be one of the following: +, -, *, /. */ static int clo_parse_range(struct benchmark_clo *clo, const char *arg, clo_parse_single_fn parse_single, clo_eval_range_fn eval_range, struct clo_vec_vlist *vlist) { char *str_first = (char *)malloc(strlen(arg) + 1); assert(str_first != NULL); char *str_step = (char *)malloc(strlen(arg) + 1); assert(str_step != NULL); char step_type = '\0'; char *str_last = (char *)malloc(strlen(arg) + 1); assert(str_last != NULL); int ret = sscanf(arg, "%[^:]:%c%[^:]:%[^:]", str_first, &step_type, str_step, str_last); if (ret == 1) { /* single value */ uint64_t value; if (parse_single(clo, arg, &value)) { ret = -1; } else { if (clo->type == CLO_TYPE_UINT) clo_vec_vlist_add(vlist, &value, clo->type_uint.size); else clo_vec_vlist_add(vlist, &value, clo->type_int.size); ret = 0; } } else if (ret == 4) { /* range */ uint64_t first = 0; uint64_t last = 0; uint64_t step = 0; if (parse_single(clo, str_first, &first)) { ret = -1; goto out; } char *end; errno = 0; step = strtoull(str_step, &end, 10); if (errno || !end || *end != '\0') { ret = -1; goto out; } if (parse_single(clo, str_last, &last)) { ret = -1; goto out; } if (clo_check_range_params(step, step_type)) { ret = -1; goto out; } /* evaluate the range */ if (eval_range(clo, &first, &step, &last, step_type, vlist)) { ret = -1; goto out; } ret = 0; } else { ret = -1; } out: free(str_first); free(str_step); free(str_last); return ret; } /* * clo_parse_ranges -- (internal) parse ranges/values separated by commas */ static int clo_parse_ranges(struct benchmark_clo *clo, const char *arg, struct clo_vec *clovec, clo_parse_single_fn parse_single, clo_eval_range_fn eval_range) { struct clo_vec_vlist *vlist = clo_vec_vlist_alloc(); assert(vlist != NULL); int ret = 0; char *args = strdup(arg); assert(args != NULL); char *curr = args; char *next; /* iterate through all values separated by comma */ while ((next = strchr(curr, ',')) != NULL) { *next = '\0'; next++; /* parse each comma separated value as range or single value */ if ((ret = clo_parse_range(clo, curr, parse_single, eval_range, vlist))) goto out; curr = next; } /* parse each comma separated value as range or single value */ if ((ret = clo_parse_range(clo, curr, parse_single, eval_range, vlist))) goto out; /* add list of values to CLO vector */ if (clo->type == CLO_TYPE_UINT) ret = clo_vec_memcpy_list(clovec, clo->off, clo->type_uint.size, vlist); else ret = clo_vec_memcpy_list(clovec, clo->off, clo->type_int.size, vlist); out: free(args); clo_vec_vlist_free(vlist); return ret; } /* * clo_parse_int -- (internal) parse int value */ static int clo_parse_int(struct benchmark_clo *clo, const char *arg, struct clo_vec *clovec) { return clo_parse_ranges(clo, arg, clovec, clo_parse_single_int, clo_eval_range_int); } /* * clo_parse_uint -- (internal) parse uint value */ static int clo_parse_uint(struct benchmark_clo *clo, const char *arg, struct clo_vec *clovec) { return clo_parse_ranges(clo, arg, clovec, clo_parse_single_uint, clo_eval_range_uint); } /* * clo_str_flag -- (internal) convert flag value to string */ static const char * clo_str_flag(struct benchmark_clo *clo, void *addr, size_t size) { if (clo->off + sizeof(bool) > size) return NULL; bool flag = *(bool *)((char *)addr + clo->off); return flag ? "true" : "false"; } /* * clo_str_str -- (internal) convert str value to string */ static const char * clo_str_str(struct benchmark_clo *clo, void *addr, size_t size) { if (clo->off + sizeof(char *) > size) return NULL; return *(char **)((char *)addr + clo->off); } /* * clo_str_int -- (internal) convert int value to string */ static const char * clo_str_int(struct benchmark_clo *clo, void *addr, size_t size) { if (clo->off + clo->type_int.size > size) return NULL; void *val = (char *)addr + clo->off; int ret = 0; switch (clo->type_int.size) { case 1: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRId8, *(int8_t *)val); break; case 2: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRId16, *(int16_t *)val); break; case 4: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRId32, *(int32_t *)val); break; case 8: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRId64, *(int64_t *)val); break; default: return NULL; } if (ret < 0) return NULL; return str_buff; } /* * clo_str_uint -- (internal) convert uint value to string */ static const char * clo_str_uint(struct benchmark_clo *clo, void *addr, size_t size) { if (clo->off + clo->type_uint.size > size) return NULL; void *val = (char *)addr + clo->off; int ret = 0; switch (clo->type_uint.size) { case 1: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRIu8, *(uint8_t *)val); break; case 2: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRIu16, *(uint16_t *)val); break; case 4: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRIu32, *(uint32_t *)val); break; case 8: ret = snprintf(str_buff, STR_BUFF_SIZE, "%" PRIu64, *(uint64_t *)val); break; default: return NULL; } if (ret < 0) return NULL; return str_buff; } /* * clo_parse -- (internal) array with functions for parsing CLOs */ static clo_parse_fn clo_parse[CLO_TYPE_MAX] = { /* [CLO_TYPE_FLAG] = */ clo_parse_flag, /* [CLO_TYPE_STR] = */ clo_parse_str, /* [CLO_TYPE_INT] = */ clo_parse_int, /* [CLO_TYPE_UINT] = */ clo_parse_uint, }; /* * clo_str -- (internal) array with functions for converting to string */ static clo_str_fn clo_str[CLO_TYPE_MAX] = { /* [CLO_TYPE_FLAG] = */ clo_str_flag, /* [CLO_TYPE_STR] = */ clo_str_str, /* [CLO_TYPE_INT] = */ clo_str_int, /* [CLO_TYPE_UINT] = */ clo_str_uint, }; /* * clo_get_by_short -- (internal) return CLO with specified short opt */ static struct benchmark_clo * clo_get_by_short(struct benchmark_clo *clos, size_t nclo, char opt_short) { size_t i; for (i = 0; i < nclo; i++) { if (clos[i].opt_short == opt_short) return &clos[i]; } return NULL; } /* * clo_get_by_long -- (internal) return CLO with specified long opt */ static struct benchmark_clo * clo_get_by_long(struct benchmark_clo *clos, size_t nclo, const char *opt_long) { size_t i; for (i = 0; i < nclo; i++) { if (strcmp(clos[i].opt_long, opt_long) == 0) return &clos[i]; } return NULL; } /* * clo_get_optstr -- (internal) returns option string from CLOs * * This function returns option string which contains all short * options from CLO structure. * The returned value must be freed by caller. */ static char * clo_get_optstr(struct benchmark_clo *clos, size_t nclo) { size_t i; char *optstr; char *ptr; /* * In worst case every option requires an argument * so we need space for ':' character + terminating * NULL. */ size_t optstrlen = nclo * 2 + 1; optstr = (char *)calloc(1, optstrlen); assert(optstr != NULL); ptr = optstr; for (i = 0; i < nclo; i++) { if (clos[i].opt_short) { *(ptr++) = clos[i].opt_short; if (clos[i].type != CLO_TYPE_FLAG) *(ptr++) = ':'; } } return optstr; } /* * clo_get_long_options -- (internal) allocate long options structure * * This function allocates structure for long options and fills all * entries according to values from becnhmark_clo. This is essentially * conversion from struct benchmark_clo to struct option. * The returned value must be freed by caller. */ static struct option * clo_get_long_options(struct benchmark_clo *clos, size_t nclo) { size_t i; struct option *options; options = (struct option *)calloc(nclo + 1, sizeof(struct option)); assert(options != NULL); for (i = 0; i < nclo; i++) { options[i].name = clos[i].opt_long; options[i].val = clos[i].opt_short; /* no optional arguments */ if (clos[i].type == CLO_TYPE_FLAG) { options[i].has_arg = no_argument; } else { options[i].has_arg = required_argument; } } return options; } /* * clo_set_defaults -- (internal) set default values * * Default values are stored as strings in CLO * structure so this function parses default values in * the same manner as values passed by user. Returns -1 * if argument was not passed by user and default value * is missing. */ static int clo_set_defaults(struct benchmark_clo *clos, size_t nclo, struct clo_vec *clovec) { size_t i; for (i = 0; i < nclo; i++) { if (clos[i].used) continue; /* * If option was not used and default value * is not specified, return error. Otherwise * parse the default value in the same way as * values passed by user. Except for the flag. * If the flag default value was not specified * assign "false" value to it. */ if (clos[i].def) { if (clo_parse[clos[i].type](&clos[i], clos[i].def, clovec)) return -1; } else if (clos[i].type == CLO_TYPE_FLAG) { if (clo_parse[clos[i].type](&clos[i], "false", clovec)) return -1; } else { printf("'%s' is required option\n", clos[i].opt_long); return -1; } } return 0; } /* * benchmark_clo_parse -- parse CLOs and store values in desired structure * * This function parses command line arguments according to information * from CLOs structure. The parsed values are stored in CLO vector * pointed by clovec. If any of command line options are not passed by user, * the default value is stored if exists. Otherwise it means the argument is * required and error is returned. * * - argc - number of command line options passed by user * - argv - command line options passed by user * - clos - description of available command line options * - nclos - number of available command line options * - clovec - vector of arguments */ int benchmark_clo_parse(int argc, char *argv[], struct benchmark_clo *clos, ssize_t nclos, struct clo_vec *clovec) { char *optstr; struct option *options; int ret = 0; int opt; int optindex; /* convert CLOs to option string and long options structure */ optstr = clo_get_optstr(clos, nclos); options = clo_get_long_options(clos, nclos); /* parse CLOs as long and/or short options */ while ((opt = getopt_long(argc, argv, optstr, options, &optindex)) != -1) { struct benchmark_clo *clo = NULL; if (opt) { clo = clo_get_by_short(clos, nclos, opt); } else { assert(optindex < nclos); clo = &clos[optindex]; } if (!clo) { ret = -1; goto out; } /* invoke parser according to type of CLO */ assert(clo->type < CLO_TYPE_MAX); ret = clo_parse[clo->type](clo, optarg, clovec); if (ret) goto out; /* mark CLO as used */ clo->used = optarg != NULL || clo->type == CLO_TYPE_FLAG; } if (optind < argc) { fprintf(stderr, "Unknown option: %s\n", argv[optind]); ret = -1; goto out; } /* parse unused CLOs with default values */ ret = clo_set_defaults(clos, nclos, clovec); out: free(options); free(optstr); if (ret) errno = EINVAL; return ret; } /* * benchmark_clo_parse_scenario -- parse CLOs from scenario * * This function parses command line arguments according to information * from CLOs structure. The parsed values are stored in CLO vector * pointed by clovec. If any of command line options are not passed by user, * the default value is stored if exists. Otherwise it means the argument is * required and error is returned. * * - scenario - scenario with key value arguments * - clos - description of available command line options * - nclos - number of available command line options * - clovec - vector of arguments */ int benchmark_clo_parse_scenario(struct scenario *scenario, struct benchmark_clo *clos, size_t nclos, struct clo_vec *clovec) { struct kv *kv; FOREACH_KV(kv, scenario) { struct benchmark_clo *clo = clo_get_by_long(clos, nclos, kv->key); if (!clo) { fprintf(stderr, "unrecognized option -- '%s'\n", kv->key); return -1; } assert(clo->type < CLO_TYPE_MAX); if (clo_parse[clo->type](clo, kv->value, clovec)) { fprintf(stderr, "parsing option -- '%s' failed\n", kv->value); return -1; } /* mark CLO as used */ clo->used = 1; } return clo_set_defaults(clos, nclos, clovec); } /* * benchmark_override_clos_in_scenario - parse the command line arguments and * override/add the parameters in/to the scenario by replacing/adding the kv * struct in/to the scenario. * * - scenario - scenario with key value arguments * - argc - command line arguments number * - argv - command line arguments vector * - clos - description of available command line options * - nclos - number of available command line options */ int benchmark_override_clos_in_scenario(struct scenario *scenario, int argc, char *argv[], struct benchmark_clo *clos, int nclos) { char *optstr; struct option *options; int ret = 0; int opt; int optindex; const char *true_str = "true"; /* convert CLOs to option string and long options structure */ optstr = clo_get_optstr(clos, nclos); options = clo_get_long_options(clos, nclos); /* parse CLOs as long and/or short options */ while ((opt = getopt_long(argc, argv, optstr, options, &optindex)) != -1) { struct benchmark_clo *clo = NULL; if (opt) { clo = clo_get_by_short(clos, nclos, opt); } else { assert(optindex < nclos); clo = &clos[optindex]; } if (!clo) { ret = -1; goto out; } /* Check if the given clo is defined in the scenario */ struct kv *kv = find_kv_in_scenario(clo->opt_long, scenario); if (kv) { /* replace the value in the scenario */ if (optarg != NULL && clo->type != CLO_TYPE_FLAG) { free(kv->value); kv->value = strdup(optarg); } else if (optarg == NULL && clo->type == CLO_TYPE_FLAG) { free(kv->value); kv->value = strdup(true_str); } else { ret = -1; goto out; } } else { /* add a new param to the scenario */ if (optarg != NULL && clo->type != CLO_TYPE_FLAG) { kv = kv_alloc(clo->opt_long, optarg); TAILQ_INSERT_TAIL(&scenario->head, kv, next); } else if (optarg == NULL && clo->type == CLO_TYPE_FLAG) { kv = kv_alloc(clo->opt_long, true_str); TAILQ_INSERT_TAIL(&scenario->head, kv, next); } else { ret = -1; goto out; } } } if (optind < argc) { fprintf(stderr, "Unknown option: %s\n", argv[optind]); ret = -1; goto out; } out: free(options); free(optstr); if (ret) errno = EINVAL; return ret; } /* * benchmark_clo_str -- converts command line option to string * * According to command line option type and parameters, converts * the value from structure pointed by args of size size. */ const char * benchmark_clo_str(struct benchmark_clo *clo, void *args, size_t size) { assert(clo->type < CLO_TYPE_MAX); return clo_str[clo->type](clo, args, size); } /* * clo_get_scenarios - search the command line arguments for scenarios listed in * available_scenarios and put them in found_scenarios. Returns the number of * found scenarios in the cmd line or -1 on error. The passed cmd line * args should contain the scenario name(s) as the first argument(s) - starting * from index 0 */ int clo_get_scenarios(int argc, char *argv[], struct scenarios *available_scenarios, struct scenarios *found_scenarios) { assert(argv != NULL); assert(available_scenarios != NULL); assert(found_scenarios != NULL); if (argc <= 0) { fprintf(stderr, "clo get scenarios, argc invalid value: %d\n", argc); return -1; } int tmp_argc = argc; char **tmp_argv = argv; do { struct scenario *scenario = scenarios_get_scenario(available_scenarios, *tmp_argv); if (!scenario) { fprintf(stderr, "unknown scenario: %s\n", *tmp_argv); return -1; } struct scenario *new_scenario = clone_scenario(scenario); assert(new_scenario != NULL); TAILQ_INSERT_TAIL(&found_scenarios->head, new_scenario, next); tmp_argc--; tmp_argv++; } while (tmp_argc && contains_scenarios(tmp_argc, tmp_argv, available_scenarios)); return argc - tmp_argc; } pmdk-1.4.1/src/benchmarks/clo.hpp000066400000000000000000000043571331545616200166610ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * clo.hpp -- command line options module declarations */ int benchmark_clo_parse(int argc, char *argv[], struct benchmark_clo *clos, ssize_t nclo, struct clo_vec *clovec); int benchmark_clo_parse_scenario(struct scenario *scenario, struct benchmark_clo *clos, size_t nclo, struct clo_vec *clovec); const char *benchmark_clo_str(struct benchmark_clo *clo, void *args, size_t size); int clo_get_scenarios(int argc, char *argv[], struct scenarios *available_scenarios, struct scenarios *found_scenarios); int benchmark_override_clos_in_scenario(struct scenario *scenario, int argc, char *argv[], struct benchmark_clo *clos, int nclos); pmdk-1.4.1/src/benchmarks/clo_vec.cpp000066400000000000000000000145231331545616200175050ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * clo_vec.cpp -- command line options vector definitions */ #include #include #include #include "clo_vec.hpp" /* * clo_vec_alloc -- allocate new CLO vector */ struct clo_vec * clo_vec_alloc(size_t size) { struct clo_vec *clovec = (struct clo_vec *)malloc(sizeof(*clovec)); assert(clovec != NULL); /* init list of arguments and allocations */ TAILQ_INIT(&clovec->allocs); TAILQ_INIT(&clovec->args); clovec->nallocs = 0; /* size of each struct */ clovec->size = size; /* add first struct to list */ struct clo_vec_args *args = (struct clo_vec_args *)malloc(sizeof(*args)); assert(args != NULL); args->args = calloc(1, size); assert(args->args != NULL); TAILQ_INSERT_TAIL(&clovec->args, args, next); clovec->nargs = 1; return clovec; } /* * clo_vec_free -- free CLO vector and all allocations */ void clo_vec_free(struct clo_vec *clovec) { assert(clovec != NULL); /* free all allocations */ while (!TAILQ_EMPTY(&clovec->allocs)) { struct clo_vec_alloc *alloc = TAILQ_FIRST(&clovec->allocs); TAILQ_REMOVE(&clovec->allocs, alloc, next); free(alloc->ptr); free(alloc); } /* free all arguments */ while (!TAILQ_EMPTY(&clovec->args)) { struct clo_vec_args *args = TAILQ_FIRST(&clovec->args); TAILQ_REMOVE(&clovec->args, args, next); free(args->args); free(args); } free(clovec); } /* * clo_vec_get_args -- return pointer to CLO arguments at specified index */ void * clo_vec_get_args(struct clo_vec *clovec, size_t i) { if (i >= clovec->nargs) return NULL; size_t c = 0; struct clo_vec_args *args; TAILQ_FOREACH(args, &clovec->args, next) { if (c == i) return args->args; c++; } return NULL; } /* * clo_vec_add_alloc -- add allocation to CLO vector */ int clo_vec_add_alloc(struct clo_vec *clovec, void *ptr) { struct clo_vec_alloc *alloc = (struct clo_vec_alloc *)malloc(sizeof(*alloc)); assert(alloc != NULL); alloc->ptr = ptr; TAILQ_INSERT_TAIL(&clovec->allocs, alloc, next); clovec->nallocs++; return 0; } /* * clo_vec_grow -- (internal) grow in size the CLO vector */ static void clo_vec_grow(struct clo_vec *clovec, size_t new_len) { size_t nargs = new_len - clovec->nargs; size_t i; for (i = 0; i < nargs; i++) { struct clo_vec_args *args = (struct clo_vec_args *)calloc(1, sizeof(*args)); assert(args != NULL); TAILQ_INSERT_TAIL(&clovec->args, args, next); args->args = malloc(clovec->size); assert(args->args != NULL); void *argscpy = clo_vec_get_args(clovec, i % clovec->nargs); assert(argscpy != NULL); memcpy(args->args, argscpy, clovec->size); } clovec->nargs = new_len; } /* * clo_vec_vlist_alloc -- allocate list of values */ struct clo_vec_vlist * clo_vec_vlist_alloc(void) { struct clo_vec_vlist *list = (struct clo_vec_vlist *)malloc(sizeof(*list)); assert(list != NULL); list->nvalues = 0; TAILQ_INIT(&list->head); return list; } /* * clo_vec_vlist_free -- release list of values */ void clo_vec_vlist_free(struct clo_vec_vlist *list) { assert(list != NULL); while (!TAILQ_EMPTY(&list->head)) { struct clo_vec_value *val = TAILQ_FIRST(&list->head); TAILQ_REMOVE(&list->head, val, next); free(val->ptr); free(val); } free(list); } /* * clo_vec_vlist_add -- add value to list */ void clo_vec_vlist_add(struct clo_vec_vlist *list, void *ptr, size_t size) { struct clo_vec_value *val = (struct clo_vec_value *)malloc(sizeof(*val)); assert(val != NULL); val->ptr = malloc(size); assert(val->ptr != NULL); memcpy(val->ptr, ptr, size); TAILQ_INSERT_TAIL(&list->head, val, next); list->nvalues++; } /* * clo_vec_memcpy -- copy value to CLO vector * * - clovec - CLO vector * - off - offset to value in structure * - size - size of value field * - ptr - pointer to value */ int clo_vec_memcpy(struct clo_vec *clovec, size_t off, size_t size, void *ptr) { if (off + size > clovec->size) return -1; size_t i; for (i = 0; i < clovec->nargs; i++) { char *args = (char *)clo_vec_get_args(clovec, i); char *dptr = args + off; memcpy(dptr, ptr, size); } return 0; } /* * clo_vec_memcpy_list -- copy values from list to CLO vector * * - clovec - CLO vector * - off - offset to value in structure * - size - size of value field * - list - list of values */ int clo_vec_memcpy_list(struct clo_vec *clovec, size_t off, size_t size, struct clo_vec_vlist *list) { if (off + size > clovec->size) return -1; size_t len = clovec->nargs; if (list->nvalues > 1) clo_vec_grow(clovec, clovec->nargs * list->nvalues); struct clo_vec_value *value; size_t value_i = 0; size_t i; TAILQ_FOREACH(value, &list->head, next) { for (i = value_i * len; i < (value_i + 1) * len; i++) { char *args = (char *)clo_vec_get_args(clovec, i); char *dptr = args + off; memcpy(dptr, value->ptr, size); } value_i++; } return 0; } pmdk-1.4.1/src/benchmarks/clo_vec.hpp000066400000000000000000000052561331545616200175150ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * clo_vec.hpp -- command line options vector declarations */ #include "queue.h" #include struct clo_vec_args { TAILQ_ENTRY(clo_vec_args) next; void *args; }; struct clo_vec_alloc { TAILQ_ENTRY(clo_vec_alloc) next; void *ptr; }; struct clo_vec_value { TAILQ_ENTRY(clo_vec_value) next; void *ptr; }; struct clo_vec_vlist { TAILQ_HEAD(valueshead, clo_vec_value) head; size_t nvalues; }; struct clo_vec { size_t size; TAILQ_HEAD(argshead, clo_vec_args) args; size_t nargs; TAILQ_HEAD(allochead, clo_vec_alloc) allocs; size_t nallocs; }; struct clo_vec *clo_vec_alloc(size_t size); void clo_vec_free(struct clo_vec *clovec); void *clo_vec_get_args(struct clo_vec *clovec, size_t i); int clo_vec_add_alloc(struct clo_vec *clovec, void *ptr); int clo_vec_memcpy(struct clo_vec *clovec, size_t off, size_t size, void *ptr); int clo_vec_memcpy_list(struct clo_vec *clovec, size_t off, size_t size, struct clo_vec_vlist *list); struct clo_vec_vlist *clo_vec_vlist_alloc(void); void clo_vec_vlist_free(struct clo_vec_vlist *list); void clo_vec_vlist_add(struct clo_vec_vlist *list, void *ptr, size_t size); pmdk-1.4.1/src/benchmarks/config_reader.cpp000066400000000000000000000162341331545616200206630ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * config_reader.cpp -- config reader module definitions */ #include #include #include #include #include #include #include "config_reader.hpp" #include "scenario.hpp" #define SECTION_GLOBAL "global" #define KEY_BENCHMARK "bench" #define KEY_GROUP "group" /* * config_reader -- handle structure */ struct config_reader { GKeyFile *key_file; }; /* * config_reader_alloc -- allocate config reader */ struct config_reader * config_reader_alloc(void) { struct config_reader *cr = (struct config_reader *)malloc(sizeof(*cr)); assert(cr != NULL); cr->key_file = g_key_file_new(); if (!cr->key_file) goto err; return cr; err: free(cr); return NULL; } /* * config_reader_read -- read config file */ int config_reader_read(struct config_reader *cr, const char *fname) { if (g_key_file_load_from_file(cr->key_file, fname, G_KEY_FILE_NONE, NULL) != TRUE) return -1; return 0; } /* * config_reader_free -- free config reader */ void config_reader_free(struct config_reader *cr) { g_key_file_free(cr->key_file); free(cr); } /* * is_scenario -- (internal) return true if _name_ is scenario name * * This filters out the _global_ and _config_ sections. */ static int is_scenario(const char *name) { return strcmp(name, SECTION_GLOBAL); } /* * is_argument -- (internal) return true if _name_ is argument name * * This filters out the _benchmark_ key. */ static int is_argument(const char *name) { return strcmp(name, KEY_BENCHMARK) != 0 && strcmp(name, KEY_GROUP) != 0; } /* * config_reader_get_scenarios -- return scenarios from config file * * This function reads the config file and returns a list of scenarios. * Each scenario contains a list of key/value arguments. * The scenario's arguments are merged with arguments from global section. */ int config_reader_get_scenarios(struct config_reader *cr, struct scenarios **scenarios) { /* * Read all groups. * The config file must have at least one group, otherwise * it is considered as invalid. */ gsize ngroups; gsize g; gchar **groups = g_key_file_get_groups(cr->key_file, &ngroups); assert(NULL != groups); if (!groups) return -1; /* * Check if global section is present and read keys from it. */ int ret = 0; int has_global = g_key_file_has_group(cr->key_file, SECTION_GLOBAL) == TRUE; gsize ngkeys; gchar **gkeys = NULL; struct scenarios *s; if (has_global) { gkeys = g_key_file_get_keys(cr->key_file, SECTION_GLOBAL, &ngkeys, NULL); assert(NULL != gkeys); if (!gkeys) { ret = -1; goto err_groups; } } s = scenarios_alloc(); assert(NULL != s); if (!s) { ret = -1; goto err_gkeys; } for (g = 0; g < ngroups; g++) { /* * Check whether a group is a scenario * or global section. */ if (!is_scenario(groups[g])) continue; /* * Check for KEY_BENCHMARK which contains benchmark name. * If not present the benchmark name is the same as the * name of the section. */ struct scenario *scenario = NULL; if (g_key_file_has_key(cr->key_file, groups[g], KEY_BENCHMARK, NULL) == FALSE) { scenario = scenario_alloc(groups[g], groups[g]); assert(scenario != NULL); } else { gchar *benchmark = g_key_file_get_value( cr->key_file, groups[g], KEY_BENCHMARK, NULL); assert(benchmark != NULL); if (!benchmark) { ret = -1; goto err_scenarios; } scenario = scenario_alloc(groups[g], benchmark); assert(scenario != NULL); free(benchmark); } gsize k; if (has_global) { /* * Merge key/values from global section. */ for (k = 0; k < ngkeys; k++) { if (g_key_file_has_key(cr->key_file, groups[g], gkeys[k], NULL) == TRUE) continue; if (!is_argument(gkeys[k])) continue; char *value = g_key_file_get_value( cr->key_file, SECTION_GLOBAL, gkeys[k], NULL); assert(NULL != value); if (!value) { ret = -1; goto err_scenarios; } struct kv *kv = kv_alloc(gkeys[k], value); assert(NULL != kv); free(value); if (!kv) { ret = -1; goto err_scenarios; } TAILQ_INSERT_TAIL(&scenario->head, kv, next); } } /* check for group name */ if (g_key_file_has_key(cr->key_file, groups[g], KEY_GROUP, NULL) != FALSE) { gchar *group = g_key_file_get_value( cr->key_file, groups[g], KEY_GROUP, NULL); assert(group != NULL); scenario_set_group(scenario, group); } else if (g_key_file_has_key(cr->key_file, SECTION_GLOBAL, KEY_GROUP, NULL) != FALSE) { gchar *group = g_key_file_get_value( cr->key_file, SECTION_GLOBAL, KEY_GROUP, NULL); scenario_set_group(scenario, group); } gsize nkeys; gchar **keys = g_key_file_get_keys(cr->key_file, groups[g], &nkeys, NULL); assert(NULL != keys); if (!keys) { ret = -1; goto err_scenarios; } /* * Read key/values from the scenario's section. */ for (k = 0; k < nkeys; k++) { if (!is_argument(keys[k])) continue; char *value = g_key_file_get_value( cr->key_file, groups[g], keys[k], NULL); assert(NULL != value); if (!value) { ret = -1; g_strfreev(keys); goto err_scenarios; } struct kv *kv = kv_alloc(keys[k], value); assert(NULL != kv); free(value); if (!kv) { g_strfreev(keys); ret = -1; goto err_scenarios; } TAILQ_INSERT_TAIL(&scenario->head, kv, next); } g_strfreev(keys); TAILQ_INSERT_TAIL(&s->head, scenario, next); } g_strfreev(gkeys); g_strfreev(groups); *scenarios = s; return 0; err_scenarios: scenarios_free(s); err_gkeys: g_strfreev(gkeys); err_groups: g_strfreev(groups); return ret; } pmdk-1.4.1/src/benchmarks/config_reader.hpp000066400000000000000000000036371331545616200206730ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * config_reader.hpp -- config reader module declarations */ struct config_reader; struct config_reader *config_reader_alloc(void); int config_reader_read(struct config_reader *cr, const char *fname); void config_reader_free(struct config_reader *cr); int config_reader_get_scenarios(struct config_reader *cr, struct scenarios **scenarios); pmdk-1.4.1/src/benchmarks/config_reader_win.cpp000066400000000000000000000210511331545616200215310ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * config_reader_win.cpp -- config reader module definitions */ #include #include #include #include #include #include "config_reader.hpp" #include "queue.h" #include "scenario.hpp" #define SECTION_GLOBAL TEXT("global") #define KEY_BENCHMARK TEXT("bench") #define KEY_GROUP TEXT("group") /* * Maximum section size according to MSDN documentation */ #define SIZEOF_SECTION 32767 #define NULL_LIST_EMPTY(x) (_tcslen(x) == 0) #define NULL_LIST_NEXT(x) ((x) += (_tcslen(x) + 1)) #define KV_LIST_EMPTY(x) (_tcslen(x) == 0) #define KV_FIRST(x) #define KV_LIST_NEXT(x) \ ((x) += (_tcslen(x) + 1), x += (_tcslen(x) + 1), \ (x) = kv_list_skip_comment(x)) #define KV_LIST_KEY(x) (x) #define KV_LIST_VALUE(x) ((x) + _tcslen(x) + 1) #define KV_LIST_INIT(x) kv_list_init(x) #define LIST LPTSTR #define KV_LIST LPTSTR /* * kv_list_skip_comment -- skip comment lines in ini file */ static KV_LIST kv_list_skip_comment(KV_LIST list) { while (list[0] == TEXT('#')) list += (_tcslen(list) + 1); return list; } /* * kv_list_init -- init KV list */ static KV_LIST kv_list_init(LPTSTR list) { list = kv_list_skip_comment(list); for (KV_LIST it = list; !KV_LIST_EMPTY(it); KV_LIST_NEXT(it)) { LPTSTR c = _tcsstr(it, TEXT("=")); if (c == NULL) return NULL; *c = TEXT('\0'); } return list; } /* * config_reader -- handle structure */ struct config_reader { LPTSTR lpFileName; }; /* * config_reader_alloc -- allocate config reader */ struct config_reader * config_reader_alloc(void) { struct config_reader *cr = (struct config_reader *)malloc(sizeof(*cr)); if (cr == NULL) return NULL; return cr; } /* * config_reader_read -- read config file */ int config_reader_read(struct config_reader *cr, const char *fname) { DWORD len = 0; LPTSTR buf = TEXT(" "); /* get the length of the full pathname incl. terminating null char */ len = GetFullPathName((LPTSTR)fname, 0, buf, NULL); if (len == 0) { /* the function failed */ return -1; } else { /* allocate a buffer large enough to store the pathname */ LPTSTR buffer = (LPTSTR)malloc(len * sizeof(TCHAR)); DWORD ret = GetFullPathName((LPTSTR)fname, len, buffer, NULL); if (_taccess(buffer, 0) != 0) { printf("%s", strerror(errno)); return -1; } cr->lpFileName = (LPTSTR)buffer; } return 0; } /* * config_reader_free -- free config reader */ void config_reader_free(struct config_reader *cr) { free(cr); } /* * is_scenario -- (internal) return true if _name_ is scenario name * * This filters out the _global_ and _config_ sections. */ static int is_scenario(LPTSTR name) { return _tcscmp(name, SECTION_GLOBAL); } /* * is_argument -- (internal) return true if _name_ is argument name * * This filters out the _benchmark_ key. */ static int is_argument(LPTSTR name) { return _tcscmp(name, KEY_BENCHMARK) != 0 && _tcscmp(name, KEY_GROUP) != 0; } /* * config_reader_get_scenarios -- return scenarios from config file * * This function reads the config file and returns a list of scenarios. * Each scenario contains a list of key/value arguments. * The scenario's arguments are merged with arguments from global section. */ int config_reader_get_scenarios(struct config_reader *cr, struct scenarios **scenarios) { /* * Read all groups. * The config file must have at least one group, otherwise * it is considered as invalid. */ int ret = 0; TCHAR *sections = (TCHAR *)malloc(sizeof(TCHAR) * SIZEOF_SECTION); if (!sections) return -1; GetPrivateProfileSectionNames(sections, SIZEOF_SECTION, cr->lpFileName); if (NULL_LIST_EMPTY(sections)) { ret = -1; goto err_sections; } /* * Check if global section is present and read it. */ TCHAR *global = (TCHAR *)malloc(sizeof(TCHAR) * SIZEOF_SECTION); if (!global) return -1; GetPrivateProfileSection(SECTION_GLOBAL, global, SIZEOF_SECTION, cr->lpFileName); KV_LIST global_kv = KV_LIST_INIT(global); int has_global = !KV_LIST_EMPTY(global_kv); struct scenarios *s = scenarios_alloc(); assert(NULL != s); if (!s) { ret = -1; goto err_gkeys; } LPTSTR global_group = NULL; for (KV_LIST it = global_kv; !KV_LIST_EMPTY(it); KV_LIST_NEXT(it)) { if (_tcscmp(KV_LIST_KEY(it), KEY_GROUP) == 0) { global_group = KV_LIST_VALUE(it); break; } } TCHAR *section; for (LPTSTR group_name = sections; !NULL_LIST_EMPTY(group_name); group_name = NULL_LIST_NEXT(group_name)) { /* * Check whether a group is a scenario * or global section. */ if (!is_scenario(group_name)) continue; /* * Check for KEY_BENCHMARK which contains benchmark name. * If not present the benchmark name is the same as the * name of the section. */ section = (TCHAR *)malloc(sizeof(TCHAR) * SIZEOF_SECTION); if (!section) ret = -1; GetPrivateProfileSection(group_name, section, SIZEOF_SECTION, cr->lpFileName); KV_LIST section_kv = KV_LIST_INIT(section); struct scenario *scenario = NULL; LPTSTR name = NULL; LPTSTR group = NULL; for (KV_LIST it = section_kv; !KV_LIST_EMPTY(it); KV_LIST_NEXT(it)) { if (_tcscmp(KV_LIST_KEY(it), KEY_BENCHMARK) == 0) { name = KV_LIST_VALUE(it); } if (_tcscmp(KV_LIST_KEY(it), KEY_GROUP) == 0) { group = KV_LIST_VALUE(it); } } if (name == NULL) { scenario = scenario_alloc((const char *)group_name, (const char *)group_name); } else { scenario = scenario_alloc((const char *)group_name, (const char *)name); } assert(scenario != NULL); if (has_global) { /* * Merge key/values from global section. */ for (KV_LIST it = global_kv; !KV_LIST_EMPTY(it); KV_LIST_NEXT(it)) { LPTSTR key = KV_LIST_KEY(it); if (!is_argument(key)) continue; LPTSTR value = KV_LIST_VALUE(it); assert(NULL != value); if (!value) { ret = -1; goto err_scenarios; } struct kv *kv = kv_alloc((const char *)key, (const char *)value); assert(NULL != kv); if (!kv) { ret = -1; goto err_scenarios; } TAILQ_INSERT_TAIL(&scenario->head, kv, next); } } /* check for group name */ if (group) { scenario_set_group(scenario, (const char *)group); } else if (global_group) { scenario_set_group(scenario, (const char *)global_group); } for (KV_LIST it = section_kv; !KV_LIST_EMPTY(it); KV_LIST_NEXT(it)) { LPTSTR key = KV_LIST_KEY(it); if (!is_argument(key)) continue; LPTSTR value = KV_LIST_VALUE(it); assert(NULL != value); if (!value) { ret = -1; goto err_scenarios; } struct kv *kv = kv_alloc((const char *)key, (const char *)value); assert(NULL != kv); if (!kv) { ret = -1; goto err_scenarios; } TAILQ_INSERT_TAIL(&scenario->head, kv, next); } TAILQ_INSERT_TAIL(&s->head, scenario, next); free(section); } *scenarios = s; free(global); free(sections); return 0; err_scenarios: free(section); scenarios_free(s); err_gkeys: free(global); err_sections: free(sections); return ret; } pmdk-1.4.1/src/benchmarks/log.cpp000066400000000000000000000423071331545616200166550ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * log.cpp -- pmemlog benchmarks definitions */ #include #include #include #include #include #include #include #include "benchmark.hpp" #include "libpmemlog.h" #include "os.h" /* * Size of pool header, pool descriptor * and additional page alignment overhead */ #define POOL_HDR_SIZE (3 * 4096) #define MIN_VEC_SIZE 1 /* * prog_args - benchmark's specific command line arguments */ struct prog_args { unsigned seed; /* seed for pseudo-random generator */ bool rand; /* use random numbers */ int vec_size; /* vector size */ size_t el_size; /* size of single append */ size_t min_size; /* minimum size for random mode */ bool no_warmup; /* don't do warmup */ bool fileio; /* use file io instead of pmemlog */ }; /* * thread_info - thread specific data */ struct log_worker_info { unsigned seed; struct iovec *iov; /* io vector */ char *buf; /* buffer for write/read operations */ size_t buf_size; /* buffer size */ size_t buf_ptr; /* pointer for read operations */ size_t *rand_sizes; size_t *vec_sizes; /* sum of sizes in vector */ }; /* * log_bench - main context of benchmark */ struct log_bench { size_t psize; /* size of pool */ PMEMlogpool *plp; /* pmemlog handle */ struct prog_args *args; /* benchmark specific arguments */ int fd; /* file descriptor for file io mode */ unsigned seed; /* * Pointer to the main benchmark operation. The appropriate function * will be assigned depending on the benchmark specific arguments. */ int (*func_op)(struct benchmark *, struct operation_info *); }; /* * do_warmup -- do warmup by writing the whole pool area */ static int do_warmup(struct log_bench *lb, size_t nops) { int ret = 0; size_t bsize = lb->args->vec_size * lb->args->el_size; char *buf = (char *)calloc(1, bsize); if (!buf) { perror("calloc"); return -1; } if (!lb->args->fileio) { for (size_t i = 0; i < nops; i++) { if (pmemlog_append(lb->plp, buf, lb->args->el_size) < 0) { ret = -1; perror("pmemlog_append"); goto out; } } pmemlog_rewind(lb->plp); } else { for (size_t i = 0; i < nops; i++) { if (write(lb->fd, buf, (unsigned)lb->args->el_size) != (ssize_t)lb->args->el_size) { ret = -1; perror("write"); os_close(lb->fd); goto out; } } if (os_lseek(lb->fd, 0, SEEK_SET) < 0) { ret = -1; perror("lseek"); os_close(lb->fd); } } out: free(buf); return ret; } /* * log_append -- performs pmemlog_append operation */ static int log_append(struct benchmark *bench, struct operation_info *info) { struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); assert(lb); struct log_worker_info *worker_info = (struct log_worker_info *)info->worker->priv; assert(worker_info); size_t size = lb->args->rand ? worker_info->rand_sizes[info->index] : lb->args->el_size; if (pmemlog_append(lb->plp, worker_info->buf, size) < 0) { perror("pmemlog_append"); return -1; } return 0; } /* * log_appendv -- performs pmemlog_appendv operation */ static int log_appendv(struct benchmark *bench, struct operation_info *info) { struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); assert(lb); struct log_worker_info *worker_info = (struct log_worker_info *)info->worker->priv; assert(worker_info); struct iovec *iov = &worker_info->iov[info->index * lb->args->vec_size]; if (pmemlog_appendv(lb->plp, iov, lb->args->vec_size) < 0) { perror("pmemlog_appendv"); return -1; } return 0; } /* * fileio_append -- performs fileio append operation */ static int fileio_append(struct benchmark *bench, struct operation_info *info) { struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); assert(lb); struct log_worker_info *worker_info = (struct log_worker_info *)info->worker->priv; assert(worker_info); size_t size = lb->args->rand ? worker_info->rand_sizes[info->index] : lb->args->el_size; if (write(lb->fd, worker_info->buf, (unsigned)size) != (ssize_t)size) { perror("write"); return -1; } return 0; } /* * fileio_appendv -- performs fileio appendv operation */ static int fileio_appendv(struct benchmark *bench, struct operation_info *info) { struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); assert(lb != NULL); struct log_worker_info *worker_info = (struct log_worker_info *)info->worker->priv; assert(worker_info); struct iovec *iov = &worker_info->iov[info->index * lb->args->vec_size]; size_t vec_size = worker_info->vec_sizes[info->index]; if (os_writev(lb->fd, iov, lb->args->vec_size) != (ssize_t)vec_size) { perror("writev"); return -1; } return 0; } /* * log_process_data -- callback function for pmemlog_walk. */ static int log_process_data(const void *buf, size_t len, void *arg) { struct log_worker_info *worker_info = (struct log_worker_info *)arg; size_t left = worker_info->buf_size - worker_info->buf_ptr; if (len > left) { worker_info->buf_ptr = 0; left = worker_info->buf_size; } len = len < left ? len : left; assert(len <= left); void *buff = &worker_info->buf[worker_info->buf_ptr]; memcpy(buff, buf, len); worker_info->buf_ptr += len; return 1; } /* * fileio_read -- perform single fileio read */ static int fileio_read(int fd, ssize_t len, struct log_worker_info *worker_info) { ssize_t left = worker_info->buf_size - worker_info->buf_ptr; if (len > left) { worker_info->buf_ptr = 0; left = worker_info->buf_size; } len = len < left ? len : left; assert(len <= left); size_t off = worker_info->buf_ptr; void *buff = &worker_info->buf[off]; if ((len = pread(fd, buff, len, off)) < 0) return -1; worker_info->buf_ptr += len; return 1; } /* * log_read_op -- perform read operation */ static int log_read_op(struct benchmark *bench, struct operation_info *info) { struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); assert(lb); struct log_worker_info *worker_info = (struct log_worker_info *)info->worker->priv; assert(worker_info); worker_info->buf_ptr = 0; size_t chunk_size = lb->args->rand ? worker_info->rand_sizes[info->index] : lb->args->el_size; if (!lb->args->fileio) { pmemlog_walk(lb->plp, chunk_size, log_process_data, worker_info); return 0; } int ret; while ((ret = fileio_read(lb->fd, chunk_size, worker_info)) == 1) ; return ret; } /* * log_init_worker -- init benchmark worker */ static int log_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { int ret = 0; struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); size_t i_size, n_vectors; assert(lb); struct log_worker_info *worker_info = (struct log_worker_info *)malloc( sizeof(struct log_worker_info)); if (!worker_info) { perror("malloc"); return -1; } /* allocate buffer for append / read */ worker_info->buf_size = lb->args->el_size * lb->args->vec_size; worker_info->buf = (char *)malloc(worker_info->buf_size); if (!worker_info->buf) { perror("malloc"); ret = -1; goto err_free_worker_info; } /* * For random mode, each operation has its own vector with * random sizes. Otherwise there is only one vector with * equal sizes. */ n_vectors = args->n_ops_per_thread; worker_info->iov = (struct iovec *)malloc( n_vectors * lb->args->vec_size * sizeof(struct iovec)); if (!worker_info->iov) { perror("malloc"); ret = -1; goto err_free_buf; } if (lb->args->rand) { /* each thread has random seed */ worker_info->seed = (unsigned)os_rand_r(&lb->seed); /* each vector element has its own random size */ size_t n_sizes = args->n_ops_per_thread * lb->args->vec_size; worker_info->rand_sizes = (size_t *)malloc( n_sizes * sizeof(*worker_info->rand_sizes)); if (!worker_info->rand_sizes) { perror("malloc"); ret = -1; goto err_free_iov; } /* generate append sizes */ for (size_t i = 0; i < n_sizes; i++) { uint32_t hr = (uint32_t)os_rand_r(&worker_info->seed); uint32_t lr = (uint32_t)os_rand_r(&worker_info->seed); uint64_t r64 = (uint64_t)hr << 32 | lr; size_t width = lb->args->el_size - lb->args->min_size; worker_info->rand_sizes[i] = r64 % width + lb->args->min_size; } } else { worker_info->rand_sizes = NULL; } worker_info->vec_sizes = (size_t *)calloc( args->n_ops_per_thread, sizeof(*worker_info->vec_sizes)); if (!worker_info->vec_sizes) { perror("malloc\n"); ret = -1; goto err_free_rand_sizes; } /* fill up the io vectors */ i_size = 0; for (size_t n = 0; n < args->n_ops_per_thread; n++) { size_t buf_ptr = 0; size_t vec_off = n * lb->args->vec_size; for (int i = 0; i < lb->args->vec_size; ++i) { size_t el_size = lb->args->rand ? worker_info->rand_sizes[i_size++] : lb->args->el_size; worker_info->iov[vec_off + i].iov_base = &worker_info->buf[buf_ptr]; worker_info->iov[vec_off + i].iov_len = el_size; worker_info->vec_sizes[n] += el_size; buf_ptr += el_size; } } worker->priv = worker_info; return 0; err_free_rand_sizes: free(worker_info->rand_sizes); err_free_iov: free(worker_info->iov); err_free_buf: free(worker_info->buf); err_free_worker_info: free(worker_info); return ret; } /* * log_free_worker -- cleanup benchmark worker */ static void log_free_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct log_worker_info *worker_info = (struct log_worker_info *)worker->priv; assert(worker_info); free(worker_info->buf); free(worker_info->iov); free(worker_info->rand_sizes); free(worker_info->vec_sizes); free(worker_info); } /* * log_init -- benchmark initialization function */ static int log_init(struct benchmark *bench, struct benchmark_args *args) { int ret = 0; assert(bench); assert(args != NULL); assert(args->opts != NULL); struct benchmark_info *bench_info; struct log_bench *lb = (struct log_bench *)malloc(sizeof(struct log_bench)); if (!lb) { perror("malloc"); return -1; } lb->args = (struct prog_args *)args->opts; lb->args->el_size = args->dsize; if (lb->args->vec_size == 0) lb->args->vec_size = 1; if (lb->args->rand && lb->args->min_size > lb->args->el_size) { errno = EINVAL; ret = -1; goto err_free_lb; } if (lb->args->rand && lb->args->min_size == lb->args->el_size) lb->args->rand = false; /* align pool size to ensure that we have enough usable space */ lb->psize = ALIGN_UP(POOL_HDR_SIZE + args->n_ops_per_thread * args->n_threads * lb->args->vec_size * lb->args->el_size, Mmap_align); /* calculate a required pool size */ if (lb->psize < PMEMLOG_MIN_POOL) lb->psize = PMEMLOG_MIN_POOL; if (args->is_poolset) { if (lb->psize > args->fsize) { fprintf(stderr, "insufficient size of poolset\n"); ret = -1; goto err_free_lb; } lb->psize = 0; } bench_info = pmembench_get_info(bench); if (!lb->args->fileio) { if ((lb->plp = pmemlog_create(args->fname, lb->psize, args->fmode)) == NULL) { perror("pmemlog_create"); ret = -1; goto err_free_lb; } bench_info->operation = (lb->args->vec_size > 1) ? log_appendv : log_append; } else { int flags = O_CREAT | O_RDWR | O_SYNC; /* Create a file if it does not exist. */ if ((lb->fd = os_open(args->fname, flags, args->fmode)) < 0) { perror(args->fname); ret = -1; goto err_free_lb; } /* allocate the pmem */ if ((errno = os_posix_fallocate(lb->fd, 0, lb->psize)) != 0) { perror("posix_fallocate"); ret = -1; goto err_close; } bench_info->operation = (lb->args->vec_size > 1) ? fileio_appendv : fileio_append; } if (!lb->args->no_warmup) { size_t warmup_nops = args->n_threads * args->n_ops_per_thread; if (do_warmup(lb, warmup_nops)) { fprintf(stderr, "warmup failed\n"); ret = -1; goto err_close; } } pmembench_set_priv(bench, lb); return 0; err_close: if (lb->args->fileio) os_close(lb->fd); else pmemlog_close(lb->plp); err_free_lb: free(lb); return ret; } /* * log_exit -- cleanup benchmark */ static int log_exit(struct benchmark *bench, struct benchmark_args *args) { struct log_bench *lb = (struct log_bench *)pmembench_get_priv(bench); if (!lb->args->fileio) pmemlog_close(lb->plp); else os_close(lb->fd); free(lb); return 0; } /* command line options definition */ static struct benchmark_clo log_clo[6]; /* log_append benchmark info */ static struct benchmark_info log_append_info; /* log_read benchmark info */ static struct benchmark_info log_read_info; CONSTRUCTOR(log_costructor) void log_costructor(void) { log_clo[0].opt_short = 'r'; log_clo[0].opt_long = "random"; log_clo[0].descr = "Use random sizes for append/read"; log_clo[0].off = clo_field_offset(struct prog_args, rand); log_clo[0].type = CLO_TYPE_FLAG; log_clo[1].opt_short = 'S'; log_clo[1].opt_long = "seed"; log_clo[1].descr = "Random mode"; log_clo[1].off = clo_field_offset(struct prog_args, seed); log_clo[1].def = "1"; log_clo[1].type = CLO_TYPE_UINT; log_clo[1].type_uint.size = clo_field_size(struct prog_args, seed); log_clo[1].type_uint.base = CLO_INT_BASE_DEC; log_clo[1].type_uint.min = 1; log_clo[1].type_uint.max = UINT_MAX; log_clo[2].opt_short = 'i'; log_clo[2].opt_long = "file-io"; log_clo[2].descr = "File I/O mode"; log_clo[2].off = clo_field_offset(struct prog_args, fileio); log_clo[2].type = CLO_TYPE_FLAG; log_clo[3].opt_short = 'w'; log_clo[3].opt_long = "no-warmup"; log_clo[3].descr = "Don't do warmup", log_clo[3].type = CLO_TYPE_FLAG; log_clo[3].off = clo_field_offset(struct prog_args, no_warmup); log_clo[4].opt_short = 'm'; log_clo[4].opt_long = "min-size"; log_clo[4].descr = "Minimum size of append/read for " "random mode"; log_clo[4].type = CLO_TYPE_UINT; log_clo[4].off = clo_field_offset(struct prog_args, min_size); log_clo[4].def = "1"; log_clo[4].type_uint.size = clo_field_size(struct prog_args, min_size); log_clo[4].type_uint.base = CLO_INT_BASE_DEC; log_clo[4].type_uint.min = 1; log_clo[4].type_uint.max = UINT64_MAX; /* this one is only for log_append */ log_clo[5].opt_short = 'v'; log_clo[5].opt_long = "vector"; log_clo[5].descr = "Vector size"; log_clo[5].off = clo_field_offset(struct prog_args, vec_size); log_clo[5].def = "1"; log_clo[5].type = CLO_TYPE_INT; log_clo[5].type_int.size = clo_field_size(struct prog_args, vec_size); log_clo[5].type_int.base = CLO_INT_BASE_DEC; log_clo[5].type_int.min = MIN_VEC_SIZE; log_clo[5].type_int.max = INT_MAX; log_append_info.name = "log_append"; log_append_info.brief = "Benchmark for pmemlog_append() " "operation"; log_append_info.init = log_init; log_append_info.exit = log_exit; log_append_info.multithread = true; log_append_info.multiops = true; log_append_info.init_worker = log_init_worker; log_append_info.free_worker = log_free_worker; /* this will be assigned in log_init */ log_append_info.operation = NULL; log_append_info.measure_time = true; log_append_info.clos = log_clo; log_append_info.nclos = ARRAY_SIZE(log_clo); log_append_info.opts_size = sizeof(struct prog_args); log_append_info.rm_file = true; log_append_info.allow_poolset = true; REGISTER_BENCHMARK(log_append_info); log_read_info.name = "log_read"; log_read_info.brief = "Benchmark for pmemlog_walk() " "operation"; log_read_info.init = log_init; log_read_info.exit = log_exit; log_read_info.multithread = true; log_read_info.multiops = true; log_read_info.init_worker = log_init_worker; log_read_info.free_worker = log_free_worker; log_read_info.operation = log_read_op; log_read_info.measure_time = true; log_read_info.clos = log_clo; /* without vector */ log_read_info.nclos = ARRAY_SIZE(log_clo) - 1; log_read_info.opts_size = sizeof(struct prog_args); log_read_info.rm_file = true; log_read_info.allow_poolset = true; REGISTER_BENCHMARK(log_read_info); }; pmdk-1.4.1/src/benchmarks/map_bench.cpp000066400000000000000000000522561331545616200200140ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * map_bench.cpp -- benchmarks for: ctree, btree, rtree, rbtree, hashmap_atomic * and hashmap_tx from examples. */ #include #include "benchmark.hpp" #include "os.h" #include "os_thread.h" /* XXX: maps are build as C++ on windows and as C on linux */ #ifndef _WIN32 extern "C" { #endif #include "map.h" #include "map_btree.h" #include "map_ctree.h" #include "map_hashmap_atomic.h" #include "map_hashmap_tx.h" #include "map_rbtree.h" #include "map_rtree.h" #ifndef _WIN32 } #endif /* Values less than 3 is not suitable for current rtree implementation */ #define FACTOR 3 #define ALLOC_OVERHEAD 64 TOID_DECLARE_ROOT(struct root); struct root { TOID(struct map) map; }; #define OBJ_TYPE_NUM 1 #define swap(a, b) \ do { \ __typeof__(a) _tmp = (a); \ (a) = (b); \ (b) = _tmp; \ } while (0) /* Values less than 2048 is not suitable for current rtree implementation */ #define SIZE_PER_KEY 2048 static const struct { const char *str; const struct map_ops *ops; } map_types[] = { {"ctree", MAP_CTREE}, {"btree", MAP_BTREE}, {"rtree", MAP_RTREE}, {"rbtree", MAP_RBTREE}, {"hashmap_tx", MAP_HASHMAP_TX}, {"hashmap_atomic", MAP_HASHMAP_ATOMIC}, }; #define MAP_TYPES_NUM (sizeof(map_types) / sizeof(map_types[0])) struct map_bench_args { unsigned seed; uint64_t max_key; char *type; bool ext_tx; bool alloc; }; struct map_bench_worker { uint64_t *keys; size_t nkeys; }; struct map_bench { struct map_ctx *mapc; os_mutex_t lock; PMEMobjpool *pop; size_t pool_size; size_t nkeys; size_t init_nkeys; uint64_t *keys; struct benchmark_args *args; struct map_bench_args *margs; TOID(struct root) root; PMEMoid root_oid; TOID(struct map) map; int (*insert)(struct map_bench *, uint64_t); int (*remove)(struct map_bench *, uint64_t); int (*get)(struct map_bench *, uint64_t); }; /* * mutex_lock_nofail -- locks mutex and aborts if locking failed */ static void mutex_lock_nofail(os_mutex_t *lock) { errno = os_mutex_lock(lock); if (errno) { perror("os_mutex_lock"); abort(); } } /* * mutex_unlock_nofail -- unlocks mutex and aborts if unlocking failed */ static void mutex_unlock_nofail(os_mutex_t *lock) { errno = os_mutex_unlock(lock); if (errno) { perror("os_mutex_unlock"); abort(); } } /* * get_key -- return 64-bit random key */ static uint64_t get_key(unsigned *seed, uint64_t max_key) { unsigned key_lo = os_rand_r(seed); unsigned key_hi = os_rand_r(seed); uint64_t key = (((uint64_t)key_hi) << 32) | ((uint64_t)key_lo); if (max_key) key = key % max_key; return key; } /* * parse_map_type -- parse type of map */ static const struct map_ops * parse_map_type(const char *str) { for (unsigned i = 0; i < MAP_TYPES_NUM; i++) { if (strcmp(str, map_types[i].str) == 0) return map_types[i].ops; } return NULL; } /* * map_remove_free_op -- remove and free object from map */ static int map_remove_free_op(struct map_bench *map_bench, uint64_t key) { volatile int ret = 0; TX_BEGIN(map_bench->pop) { PMEMoid val = map_remove(map_bench->mapc, map_bench->map, key); if (OID_IS_NULL(val)) ret = -1; else pmemobj_tx_free(val); } TX_ONABORT { ret = -1; } TX_END return ret; } /* * map_remove_root_op -- remove root object from map */ static int map_remove_root_op(struct map_bench *map_bench, uint64_t key) { PMEMoid val = map_remove(map_bench->mapc, map_bench->map, key); return !OID_EQUALS(val, map_bench->root_oid); } /* * map_remove_op -- main operation for map_remove benchmark */ static int map_remove_op(struct benchmark *bench, struct operation_info *info) { struct map_bench *map_bench = (struct map_bench *)pmembench_get_priv(bench); struct map_bench_worker *tworker = (struct map_bench_worker *)info->worker->priv; uint64_t key = tworker->keys[info->index]; mutex_lock_nofail(&map_bench->lock); int ret = map_bench->remove(map_bench, key); mutex_unlock_nofail(&map_bench->lock); return ret; } /* * map_insert_alloc_op -- allocate an object and insert to map */ static int map_insert_alloc_op(struct map_bench *map_bench, uint64_t key) { int ret = 0; TX_BEGIN(map_bench->pop) { PMEMoid oid = pmemobj_tx_alloc(map_bench->args->dsize, OBJ_TYPE_NUM); ret = map_insert(map_bench->mapc, map_bench->map, key, oid); } TX_ONABORT { ret = -1; } TX_END return ret; } /* * map_insert_root_op -- insert root object to map */ static int map_insert_root_op(struct map_bench *map_bench, uint64_t key) { return map_insert(map_bench->mapc, map_bench->map, key, map_bench->root_oid); } /* * map_insert_op -- main operation for map_insert benchmark */ static int map_insert_op(struct benchmark *bench, struct operation_info *info) { struct map_bench *map_bench = (struct map_bench *)pmembench_get_priv(bench); struct map_bench_worker *tworker = (struct map_bench_worker *)info->worker->priv; uint64_t key = tworker->keys[info->index]; mutex_lock_nofail(&map_bench->lock); int ret = map_bench->insert(map_bench, key); mutex_unlock_nofail(&map_bench->lock); return ret; } /* * map_get_obj_op -- get object from map at specified key */ static int map_get_obj_op(struct map_bench *map_bench, uint64_t key) { PMEMoid val = map_get(map_bench->mapc, map_bench->map, key); return OID_IS_NULL(val); } /* * map_get_root_op -- get root object from map at specified key */ static int map_get_root_op(struct map_bench *map_bench, uint64_t key) { PMEMoid val = map_get(map_bench->mapc, map_bench->map, key); return !OID_EQUALS(val, map_bench->root_oid); } /* * map_get_op -- main operation for map_get benchmark */ static int map_get_op(struct benchmark *bench, struct operation_info *info) { struct map_bench *map_bench = (struct map_bench *)pmembench_get_priv(bench); struct map_bench_worker *tworker = (struct map_bench_worker *)info->worker->priv; uint64_t key = tworker->keys[info->index]; mutex_lock_nofail(&map_bench->lock); int ret = map_bench->get(map_bench, key); mutex_unlock_nofail(&map_bench->lock); return ret; } /* * map_common_init_worker -- common init worker function for map_* benchmarks */ static int map_common_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct map_bench_worker *tworker = (struct map_bench_worker *)calloc(1, sizeof(*tworker)); struct map_bench *tree; struct map_bench_args *targs; if (!tworker) { perror("calloc"); return -1; } tworker->nkeys = args->n_ops_per_thread; tworker->keys = (uint64_t *)malloc(tworker->nkeys * sizeof(*tworker->keys)); if (!tworker->keys) { perror("malloc"); goto err_free_worker; } tree = (struct map_bench *)pmembench_get_priv(bench); targs = (struct map_bench_args *)args->opts; if (targs->ext_tx) { int ret = pmemobj_tx_begin(tree->pop, NULL); if (ret) { (void)pmemobj_tx_end(); goto err_free_keys; } } worker->priv = tworker; return 0; err_free_keys: free(tworker->keys); err_free_worker: free(tworker); return -1; } /* * map_common_free_worker -- common cleanup worker function for map_* * benchmarks */ static void map_common_free_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct map_bench_worker *tworker = (struct map_bench_worker *)worker->priv; struct map_bench_args *targs = (struct map_bench_args *)args->opts; if (targs->ext_tx) { pmemobj_tx_commit(); (void)pmemobj_tx_end(); } free(tworker->keys); free(tworker); } /* * map_insert_init_worker -- init worker function for map_insert benchmark */ static int map_insert_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { int ret = map_common_init_worker(bench, args, worker); if (ret) return ret; struct map_bench_args *targs = (struct map_bench_args *)args->opts; assert(targs); struct map_bench_worker *tworker = (struct map_bench_worker *)worker->priv; assert(tworker); for (size_t i = 0; i < tworker->nkeys; i++) tworker->keys[i] = get_key(&targs->seed, targs->max_key); return 0; } /* * map_global_rand_keys_init -- assign random keys from global keys array */ static int map_global_rand_keys_init(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct map_bench *tree = (struct map_bench *)pmembench_get_priv(bench); assert(tree); struct map_bench_args *targs = (struct map_bench_args *)args->opts; assert(targs); struct map_bench_worker *tworker = (struct map_bench_worker *)worker->priv; assert(tworker); assert(tree->init_nkeys); /* * Assign random keys from global tree->keys array without repetitions. */ for (size_t i = 0; i < tworker->nkeys; i++) { uint64_t index = get_key(&targs->seed, tree->init_nkeys); tworker->keys[i] = tree->keys[index]; swap(tree->keys[index], tree->keys[tree->init_nkeys - 1]); tree->init_nkeys--; } return 0; } /* * map_remove_init_worker -- init worker function for map_remove benchmark */ static int map_remove_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { int ret = map_common_init_worker(bench, args, worker); if (ret) return ret; ret = map_global_rand_keys_init(bench, args, worker); if (ret) goto err_common_free_worker; return 0; err_common_free_worker: map_common_free_worker(bench, args, worker); return -1; } /* * map_bench_get_init_worker -- init worker function for map_get benchmark */ static int map_bench_get_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { int ret = map_common_init_worker(bench, args, worker); if (ret) return ret; ret = map_global_rand_keys_init(bench, args, worker); if (ret) goto err_common_free_worker; return 0; err_common_free_worker: map_common_free_worker(bench, args, worker); return -1; } /* * map_common_init -- common init function for map_* benchmarks */ static int map_common_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench); assert(args); assert(args->opts); size_t size_per_key; struct map_bench *map_bench = (struct map_bench *)calloc(1, sizeof(*map_bench)); if (!map_bench) { perror("calloc"); return -1; } map_bench->args = args; map_bench->margs = (struct map_bench_args *)args->opts; const struct map_ops *ops = parse_map_type(map_bench->margs->type); if (!ops) { fprintf(stderr, "invalid map type value specified -- '%s'\n", map_bench->margs->type); goto err_free_bench; } if (map_bench->margs->ext_tx && args->n_threads > 1) { fprintf(stderr, "external transaction " "requires single thread\n"); goto err_free_bench; } if (map_bench->margs->alloc) { map_bench->insert = map_insert_alloc_op; map_bench->remove = map_remove_free_op; map_bench->get = map_get_obj_op; } else { map_bench->insert = map_insert_root_op; map_bench->remove = map_remove_root_op; map_bench->get = map_get_root_op; } map_bench->nkeys = args->n_threads * args->n_ops_per_thread; map_bench->init_nkeys = map_bench->nkeys; size_per_key = map_bench->margs->alloc ? SIZE_PER_KEY + map_bench->args->dsize + ALLOC_OVERHEAD : SIZE_PER_KEY; map_bench->pool_size = map_bench->nkeys * size_per_key * FACTOR; if (args->is_poolset) { if (args->fsize < map_bench->pool_size) { fprintf(stderr, "insufficient poolset size\n"); goto err_free_bench; } map_bench->pool_size = 0; } else { if (map_bench->pool_size < 2 * PMEMOBJ_MIN_POOL) map_bench->pool_size = 2 * PMEMOBJ_MIN_POOL; } map_bench->pop = pmemobj_create(args->fname, "map_bench", map_bench->pool_size, args->fmode); if (!map_bench->pop) { fprintf(stderr, "pmemobj_create: %s\n", pmemobj_errormsg()); goto err_free_bench; } errno = os_mutex_init(&map_bench->lock); if (errno) { perror("os_mutex_init"); goto err_close; } map_bench->mapc = map_ctx_init(ops, map_bench->pop); if (!map_bench->mapc) { perror("map_ctx_init"); goto err_destroy_lock; } map_bench->root = POBJ_ROOT(map_bench->pop, struct root); if (TOID_IS_NULL(map_bench->root)) { fprintf(stderr, "pmemobj_root: %s\n", pmemobj_errormsg()); goto err_free_map; } map_bench->root_oid = map_bench->root.oid; if (map_create(map_bench->mapc, &D_RW(map_bench->root)->map, NULL)) { perror("map_new"); goto err_free_map; } map_bench->map = D_RO(map_bench->root)->map; pmembench_set_priv(bench, map_bench); return 0; err_free_map: map_ctx_free(map_bench->mapc); err_destroy_lock: os_mutex_destroy(&map_bench->lock); err_close: pmemobj_close(map_bench->pop); err_free_bench: free(map_bench); return -1; } /* * map_common_exit -- common cleanup function for map_* benchmarks */ static int map_common_exit(struct benchmark *bench, struct benchmark_args *args) { struct map_bench *tree = (struct map_bench *)pmembench_get_priv(bench); os_mutex_destroy(&tree->lock); map_ctx_free(tree->mapc); pmemobj_close(tree->pop); free(tree); return 0; } /* * map_keys_init -- initialize array with keys */ static int map_keys_init(struct benchmark *bench, struct benchmark_args *args) { struct map_bench *map_bench = (struct map_bench *)pmembench_get_priv(bench); assert(map_bench); struct map_bench_args *targs = (struct map_bench_args *)args->opts; assert(targs); assert(map_bench->nkeys != 0); map_bench->keys = (uint64_t *)malloc(map_bench->nkeys * sizeof(*map_bench->keys)); if (!map_bench->keys) { perror("malloc"); return -1; } int ret = 0; mutex_lock_nofail(&map_bench->lock); TX_BEGIN(map_bench->pop) { for (size_t i = 0; i < map_bench->nkeys; i++) { uint64_t key; PMEMoid oid; do { key = get_key(&targs->seed, targs->max_key); oid = map_get(map_bench->mapc, map_bench->map, key); } while (!OID_IS_NULL(oid)); if (targs->alloc) oid = pmemobj_tx_alloc(args->dsize, OBJ_TYPE_NUM); else oid = map_bench->root_oid; ret = map_insert(map_bench->mapc, map_bench->map, key, oid); if (ret) break; map_bench->keys[i] = key; } } TX_ONABORT { ret = -1; } TX_END mutex_unlock_nofail(&map_bench->lock); if (!ret) return 0; free(map_bench->keys); return ret; } /* * map_keys_exit -- cleanup of keys array */ static int map_keys_exit(struct benchmark *bench, struct benchmark_args *args) { struct map_bench *tree = (struct map_bench *)pmembench_get_priv(bench); free(tree->keys); return 0; } /* * map_remove_init -- init function for map_remove benchmark */ static int map_remove_init(struct benchmark *bench, struct benchmark_args *args) { int ret = map_common_init(bench, args); if (ret) return ret; ret = map_keys_init(bench, args); if (ret) goto err_exit_common; return 0; err_exit_common: map_common_exit(bench, args); return -1; } /* * map_remove_exit -- cleanup function for map_remove benchmark */ static int map_remove_exit(struct benchmark *bench, struct benchmark_args *args) { map_keys_exit(bench, args); return map_common_exit(bench, args); } /* * map_bench_get_init -- init function for map_get benchmark */ static int map_bench_get_init(struct benchmark *bench, struct benchmark_args *args) { int ret = map_common_init(bench, args); if (ret) return ret; ret = map_keys_init(bench, args); if (ret) goto err_exit_common; return 0; err_exit_common: map_common_exit(bench, args); return -1; } /* * map_get_exit -- exit function for map_get benchmark */ static int map_get_exit(struct benchmark *bench, struct benchmark_args *args) { map_keys_exit(bench, args); return map_common_exit(bench, args); } static struct benchmark_clo map_bench_clos[5]; static struct benchmark_info map_insert_info; static struct benchmark_info map_remove_info; static struct benchmark_info map_get_info; CONSTRUCTOR(map_bench_costructor) void map_bench_costructor(void) { map_bench_clos[0].opt_short = 'T'; map_bench_clos[0].opt_long = "type"; map_bench_clos[0].descr = "Type of container " "[ctree|btree|rtree|rbtree|hashmap_tx|hashmap_atomic]"; map_bench_clos[0].off = clo_field_offset(struct map_bench_args, type); map_bench_clos[0].type = CLO_TYPE_STR; map_bench_clos[0].def = "ctree"; map_bench_clos[1].opt_short = 's'; map_bench_clos[1].opt_long = "seed"; map_bench_clos[1].descr = "PRNG seed"; map_bench_clos[1].off = clo_field_offset(struct map_bench_args, seed); map_bench_clos[1].type = CLO_TYPE_UINT; map_bench_clos[1].def = "1"; map_bench_clos[1].type_uint.size = clo_field_size(struct map_bench_args, seed); map_bench_clos[1].type_uint.base = CLO_INT_BASE_DEC; map_bench_clos[1].type_uint.min = 1; map_bench_clos[1].type_uint.max = UINT_MAX; map_bench_clos[2].opt_short = 'M'; map_bench_clos[2].opt_long = "max-key"; map_bench_clos[2].descr = "maximum key (0 means no limit)"; map_bench_clos[2].off = clo_field_offset(struct map_bench_args, max_key); map_bench_clos[2].type = CLO_TYPE_UINT; map_bench_clos[2].def = "0"; map_bench_clos[2].type_uint.size = clo_field_size(struct map_bench_args, seed); map_bench_clos[2].type_uint.base = CLO_INT_BASE_DEC; map_bench_clos[2].type_uint.min = 0; map_bench_clos[2].type_uint.max = UINT64_MAX; map_bench_clos[3].opt_short = 'x'; map_bench_clos[3].opt_long = "external-tx"; map_bench_clos[3].descr = "Use external transaction for all " "operations (works with single " "thread only)"; map_bench_clos[3].off = clo_field_offset(struct map_bench_args, ext_tx); map_bench_clos[3].type = CLO_TYPE_FLAG; map_bench_clos[4].opt_short = 'A'; map_bench_clos[4].opt_long = "alloc"; map_bench_clos[4].descr = "Allocate object of specified size " "when inserting"; map_bench_clos[4].off = clo_field_offset(struct map_bench_args, alloc); map_bench_clos[4].type = CLO_TYPE_FLAG; map_insert_info.name = "map_insert"; map_insert_info.brief = "Inserting to tree map"; map_insert_info.init = map_common_init; map_insert_info.exit = map_common_exit; map_insert_info.multithread = true; map_insert_info.multiops = true; map_insert_info.init_worker = map_insert_init_worker; map_insert_info.free_worker = map_common_free_worker; map_insert_info.operation = map_insert_op; map_insert_info.measure_time = true; map_insert_info.clos = map_bench_clos; map_insert_info.nclos = ARRAY_SIZE(map_bench_clos); map_insert_info.opts_size = sizeof(struct map_bench_args); map_insert_info.rm_file = true; map_insert_info.allow_poolset = true; REGISTER_BENCHMARK(map_insert_info); map_remove_info.name = "map_remove"; map_remove_info.brief = "Removing from tree map"; map_remove_info.init = map_remove_init; map_remove_info.exit = map_remove_exit; map_remove_info.multithread = true; map_remove_info.multiops = true; map_remove_info.init_worker = map_remove_init_worker; map_remove_info.free_worker = map_common_free_worker; map_remove_info.operation = map_remove_op; map_remove_info.measure_time = true; map_remove_info.clos = map_bench_clos; map_remove_info.nclos = ARRAY_SIZE(map_bench_clos); map_remove_info.opts_size = sizeof(struct map_bench_args); map_remove_info.rm_file = true; map_remove_info.allow_poolset = true; REGISTER_BENCHMARK(map_remove_info); map_get_info.name = "map_get"; map_get_info.brief = "Tree lookup"; map_get_info.init = map_bench_get_init; map_get_info.exit = map_get_exit; map_get_info.multithread = true; map_get_info.multiops = true; map_get_info.init_worker = map_bench_get_init_worker; map_get_info.free_worker = map_common_free_worker; map_get_info.operation = map_get_op; map_get_info.measure_time = true; map_get_info.clos = map_bench_clos; map_get_info.nclos = ARRAY_SIZE(map_bench_clos); map_get_info.opts_size = sizeof(struct map_bench_args); map_get_info.rm_file = true; map_get_info.allow_poolset = true; REGISTER_BENCHMARK(map_get_info); } pmdk-1.4.1/src/benchmarks/obj_lanes.cpp000066400000000000000000000123361331545616200200270ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * obj_lanes.cpp -- lane benchmark definition */ #include #include #include #include "benchmark.hpp" #include "libpmemobj.h" /* an internal libpmemobj code */ extern "C" { #include "lane.h" } /* * The number of times to repeat the operation, used to get more accurate * results, because the operation time was minimal compared to the framework * overhead. */ #define OPERATION_REPEAT_COUNT 10000 /* * prog_args - command line parsed arguments */ struct prog_args { char *lane_section_name; /* lane section to be held */ }; /* * obj_bench - variables used in benchmark, passed within functions */ struct obj_bench { PMEMobjpool *pop; /* persistent pool handle */ struct prog_args *pa; /* prog_args structure */ enum lane_section_type lane_type; /* lane section to be held */ }; /* * parse_lane_section -- parses command line "--lane_section" and returns * proper lane section type enum */ static enum lane_section_type parse_lane_section(const char *arg) { if (strcmp(arg, "allocator") == 0) return LANE_SECTION_ALLOCATOR; else if (strcmp(arg, "list") == 0) return LANE_SECTION_LIST; else if (strcmp(arg, "transaction") == 0) return LANE_SECTION_TRANSACTION; else return MAX_LANE_SECTION; } /* * lanes_init -- benchmark initialization */ static int lanes_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); struct obj_bench *ob = (struct obj_bench *)malloc(sizeof(struct obj_bench)); if (ob == NULL) { perror("malloc"); return -1; } pmembench_set_priv(bench, ob); ob->pa = (struct prog_args *)args->opts; size_t psize = args->is_poolset ? 0 : PMEMOBJ_MIN_POOL; /* create pmemobj pool */ ob->pop = pmemobj_create(args->fname, "obj_lanes", psize, args->fmode); if (ob->pop == NULL) { fprintf(stderr, "%s\n", pmemobj_errormsg()); goto err; } ob->lane_type = parse_lane_section(ob->pa->lane_section_name); if (ob->lane_type == MAX_LANE_SECTION) { fprintf(stderr, "wrong lane type\n"); goto err; } return 0; err: free(ob); return -1; } /* * lanes_exit -- benchmark clean up */ static int lanes_exit(struct benchmark *bench, struct benchmark_args *args) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); pmemobj_close(ob->pop); free(ob); return 0; } /* * lanes_op -- performs the lane hold and release operations */ static int lanes_op(struct benchmark *bench, struct operation_info *info) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); struct lane_section *section; for (int i = 0; i < OPERATION_REPEAT_COUNT; i++) { lane_hold(ob->pop, §ion, ob->lane_type); lane_release(ob->pop); } return 0; } static struct benchmark_clo lanes_clo[1]; static struct benchmark_info lanes_info; CONSTRUCTOR(obj_lines_costructor) void obj_lines_costructor(void) { lanes_clo[0].opt_short = 's'; lanes_clo[0].opt_long = "lane_section"; lanes_clo[0].descr = "The lane section type: allocator," " list or transaction"; lanes_clo[0].type = CLO_TYPE_STR; lanes_clo[0].off = clo_field_offset(struct prog_args, lane_section_name); lanes_clo[0].def = "allocator"; lanes_info.name = "obj_lanes"; lanes_info.brief = "Benchmark for internal lanes " "operation"; lanes_info.init = lanes_init; lanes_info.exit = lanes_exit; lanes_info.multithread = true; lanes_info.multiops = true; lanes_info.operation = lanes_op; lanes_info.measure_time = true; lanes_info.clos = lanes_clo; lanes_info.nclos = ARRAY_SIZE(lanes_clo); lanes_info.opts_size = sizeof(struct prog_args); lanes_info.rm_file = true; lanes_info.allow_poolset = true; REGISTER_BENCHMARK(lanes_info); } pmdk-1.4.1/src/benchmarks/obj_locks.cpp000066400000000000000000000541061331545616200200410ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * obj_locks.cpp -- main source file for PMEM locks benchmark */ #include #include #include "benchmark.hpp" #include "libpmemobj.h" #include "lane.h" #include "list.h" #include "memops.h" #include "obj.h" #include "os_thread.h" #include "out.h" #include "pmalloc.h" #include "pvector.h" #include "redo.h" #include "sync.h" struct prog_args { bool use_system_threads; /* use system locks instead of PMEM locks */ unsigned n_locks; /* number of mutex/rwlock objects */ bool run_id_increment; /* increment run_id after each lock/unlock */ uint64_t runid_initial_value; /* initial value of run_id */ char *lock_mode; /* "1by1" or "all-lock" */ char *lock_type; /* "mutex", "rwlock" or "ram-mutex" */ bool use_rdlock; /* use read lock, instead of write lock */ }; /* * mutex similar to PMEMmutex, but with os_mutex_t in RAM */ typedef union padded_volatile_pmemmutex { char padding[_POBJ_CL_SIZE]; struct { uint64_t runid; os_mutex_t *mutexp; /* pointer to os_thread mutex in RAM */ } volatile_pmemmutex; } PMEM_volatile_mutex; typedef union lock_union { PMEMmutex pm_mutex; PMEMrwlock pm_rwlock; PMEM_volatile_mutex pm_vmutex; os_mutex_t pt_mutex; os_rwlock_t pt_rwlock; } lock_t; POBJ_LAYOUT_BEGIN(pmembench_lock_layout); POBJ_LAYOUT_ROOT(pmembench_lock_layout, struct my_root); POBJ_LAYOUT_TOID(pmembench_lock_layout, lock_t); POBJ_LAYOUT_END(pmembench_lock_layout); /* * my_root -- root object structure */ struct my_root { TOID(lock_t) locks; /* an array of locks */ }; /* * lock usage */ enum operation_mode { OP_MODE_1BY1, /* lock and unlock one lock at a time */ OP_MODE_ALL_LOCK, /* grab all locks, then unlock them all */ OP_MODE_MAX, }; /* * lock type */ enum benchmark_mode { BENCH_MODE_MUTEX, /* PMEMmutex vs. os_mutex_t */ BENCH_MODE_RWLOCK, /* PMEMrwlock vs. os_rwlock_t */ BENCH_MODE_VOLATILE_MUTEX, /* PMEMmutex with os_thread mutex in RAM */ BENCH_MODE_MAX }; struct mutex_bench; struct bench_ops { int (*bench_init)(struct mutex_bench *); int (*bench_exit)(struct mutex_bench *); int (*bench_op)(struct mutex_bench *); }; /* * mutex_bench -- stores variables used in benchmark, passed within functions */ struct mutex_bench { PMEMobjpool *pop; /* pointer to the persistent pool */ TOID(struct my_root) root; /* OID of the root object */ struct prog_args *pa; /* prog_args structure */ enum operation_mode lock_mode; /* lock usage mode */ enum benchmark_mode lock_type; /* lock type */ lock_t *locks; /* pointer to the array of locks */ struct bench_ops *ops; }; #define GET_VOLATILE_MUTEX(pop, mutexp) \ (os_mutex_t *)get_lock( \ (pop)->run_id, &(mutexp)->volatile_pmemmutex.runid, \ (mutexp)->volatile_pmemmutex.mutexp, \ (int (*)(void **lock, void *arg))volatile_mutex_init) typedef int (*lock_fun_wrapper)(PMEMobjpool *pop, void *lock); /* * bench_operation_1by1 -- acquire lock and unlock release locks */ static void bench_operation_1by1(lock_fun_wrapper flock, lock_fun_wrapper funlock, struct mutex_bench *mb, PMEMobjpool *pop) { for (unsigned i = 0; i < (mb)->pa->n_locks; (i)++) { void *o = (void *)(&(mb)->locks[i]); flock(pop, o); funlock(pop, o); } } /* * bench_operation_all_lock -- acquire all locks and release all locks */ static void bench_operation_all_lock(lock_fun_wrapper flock, lock_fun_wrapper funlock, struct mutex_bench *mb, PMEMobjpool *pop) { for (unsigned i = 0; i < (mb)->pa->n_locks; (i)++) { void *o = (void *)(&(mb)->locks[i]); flock(pop, o); } for (unsigned i = 0; i < (mb)->pa->n_locks; i++) { void *o = (void *)(&(mb)->locks[i]); funlock(pop, o); } } /* * get_lock -- atomically initialize and return a lock */ static void * get_lock(uint64_t pop_runid, volatile uint64_t *runid, void *lock, int (*init_lock)(void **lock, void *arg)) { uint64_t tmp_runid; while ((tmp_runid = *runid) != pop_runid) { if ((tmp_runid != (pop_runid - 1))) { if (util_bool_compare_and_swap64(runid, tmp_runid, (pop_runid - 1))) { if (init_lock(&lock, NULL)) { util_fetch_and_and64(runid, 0); return NULL; } if (util_bool_compare_and_swap64( runid, (pop_runid - 1), pop_runid) == 0) { return NULL; } } } } return lock; } /* * volatile_mutex_init -- initialize the volatile mutex object * * Allocate memory for the os_thread mutex and initialize it. * Set the runid to the same value as in the memory pool. */ static int volatile_mutex_init(os_mutex_t **mutexp, void *attr) { if (*mutexp == NULL) { *mutexp = (os_mutex_t *)malloc(sizeof(os_mutex_t)); if (*mutexp == NULL) { perror("volatile_mutex_init alloc"); return ENOMEM; } } return os_mutex_init(*mutexp); } /* * volatile_mutex_lock -- initialize the mutex object if needed and lock it */ static int volatile_mutex_lock(PMEMobjpool *pop, PMEM_volatile_mutex *mutexp) { os_mutex_t *mutex = GET_VOLATILE_MUTEX(pop, mutexp); if (mutex == NULL) return EINVAL; return os_mutex_lock(mutex); } /* * volatile_mutex_unlock -- unlock the mutex */ static int volatile_mutex_unlock(PMEMobjpool *pop, PMEM_volatile_mutex *mutexp) { os_mutex_t *mutex = (os_mutex_t *)GET_VOLATILE_MUTEX(pop, mutexp); if (mutex == NULL) return EINVAL; return os_mutex_unlock(mutex); } /* * volatile_mutex_destroy -- destroy os_thread mutex and release memory */ static int volatile_mutex_destroy(PMEMobjpool *pop, PMEM_volatile_mutex *mutexp) { os_mutex_t *mutex = (os_mutex_t *)GET_VOLATILE_MUTEX(pop, mutexp); if (mutex == NULL) return EINVAL; int ret = os_mutex_destroy(mutex); if (ret != 0) return ret; free(mutex); return 0; } /* * os_mutex_lock_wrapper -- wrapper for os_mutex_lock */ static int os_mutex_lock_wrapper(PMEMobjpool *pop, void *lock) { return os_mutex_lock((os_mutex_t *)lock); } /* * os_mutex_unlock_wrapper -- wrapper for os_mutex_unlock */ static int os_mutex_unlock_wrapper(PMEMobjpool *pop, void *lock) { return os_mutex_unlock((os_mutex_t *)lock); } /* * pmemobj_mutex_lock_wrapper -- wrapper for pmemobj_mutex_lock */ static int pmemobj_mutex_lock_wrapper(PMEMobjpool *pop, void *lock) { return pmemobj_mutex_lock(pop, (PMEMmutex *)lock); } /* * pmemobj_mutex_unlock_wrapper -- wrapper for pmemobj_mutex_unlock */ static int pmemobj_mutex_unlock_wrapper(PMEMobjpool *pop, void *lock) { return pmemobj_mutex_unlock(pop, (PMEMmutex *)lock); } /* * os_rwlock_wrlock_wrapper -- wrapper for os_rwlock_wrlock */ static int os_rwlock_wrlock_wrapper(PMEMobjpool *pop, void *lock) { return os_rwlock_wrlock((os_rwlock_t *)lock); } /* * os_rwlock_rdlock_wrapper -- wrapper for os_rwlock_rdlock */ static int os_rwlock_rdlock_wrapper(PMEMobjpool *pop, void *lock) { return os_rwlock_rdlock((os_rwlock_t *)lock); } /* * os_rwlock_unlock_wrapper -- wrapper for os_rwlock_unlock */ static int os_rwlock_unlock_wrapper(PMEMobjpool *pop, void *lock) { return os_rwlock_unlock((os_rwlock_t *)lock); } /* * pmemobj_rwlock_wrlock_wrapper -- wrapper for pmemobj_rwlock_wrlock */ static int pmemobj_rwlock_wrlock_wrapper(PMEMobjpool *pop, void *lock) { return pmemobj_rwlock_wrlock(pop, (PMEMrwlock *)lock); } /* * pmemobj_rwlock_rdlock_wrapper -- wrapper for pmemobj_rwlock_rdlock */ static int pmemobj_rwlock_rdlock_wrapper(PMEMobjpool *pop, void *lock) { return pmemobj_rwlock_rdlock(pop, (PMEMrwlock *)lock); } /* * pmemobj_rwlock_unlock_wrapper -- wrapper for pmemobj_rwlock_unlock */ static int pmemobj_rwlock_unlock_wrapper(PMEMobjpool *pop, void *lock) { return pmemobj_rwlock_unlock(pop, (PMEMrwlock *)lock); } /* * volatile_mutex_lock_wrapper -- wrapper for volatile_mutex_lock */ static int volatile_mutex_lock_wrapper(PMEMobjpool *pop, void *lock) { return volatile_mutex_lock(pop, (PMEM_volatile_mutex *)lock); } /* * volatile_mutex_unlock_wrapper -- wrapper for volatile_mutex_unlock */ static int volatile_mutex_unlock_wrapper(PMEMobjpool *pop, void *lock) { return volatile_mutex_unlock(pop, (PMEM_volatile_mutex *)lock); } /* * init_bench_mutex -- allocate and initialize mutex objects */ static int init_bench_mutex(struct mutex_bench *mb) { POBJ_ZALLOC(mb->pop, &D_RW(mb->root)->locks, lock_t, mb->pa->n_locks * sizeof(lock_t)); if (TOID_IS_NULL(D_RO(mb->root)->locks)) { perror("POBJ_ZALLOC"); return -1; } struct my_root *root = D_RW(mb->root); assert(root != NULL); mb->locks = D_RW(root->locks); assert(mb->locks != NULL); if (!mb->pa->use_system_threads) { /* initialize PMEM mutexes */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { PMEMmutex_internal *p = (PMEMmutex_internal *)&mb->locks[i]; p->pmemmutex.runid = mb->pa->runid_initial_value; os_mutex_init(&p->PMEMmutex_lock); } } else { /* initialize os_thread mutexes */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { os_mutex_t *p = (os_mutex_t *)&mb->locks[i]; os_mutex_init(p); } } return 0; } /* * exit_bench_mutex -- destroy the mutex objects and release memory */ static int exit_bench_mutex(struct mutex_bench *mb) { if (mb->pa->use_system_threads) { /* deinitialize os_thread mutex objects */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { os_mutex_t *p = (os_mutex_t *)&mb->locks[i]; os_mutex_destroy(p); } } POBJ_FREE(&D_RW(mb->root)->locks); return 0; } /* * op_bench_mutex -- lock and unlock the mutex object * * If requested, increment the run_id of the memory pool. In case of PMEMmutex * this will force the rwlock object(s) reinitialization at the lock operation. */ static int op_bench_mutex(struct mutex_bench *mb) { if (!mb->pa->use_system_threads) { if (mb->lock_mode == OP_MODE_1BY1) { bench_operation_1by1(pmemobj_mutex_lock_wrapper, pmemobj_mutex_unlock_wrapper, mb, mb->pop); } else { bench_operation_all_lock(pmemobj_mutex_lock_wrapper, pmemobj_mutex_unlock_wrapper, mb, mb->pop); } if (mb->pa->run_id_increment) mb->pop->run_id += 2; /* must be a multiple of 2 */ } else { if (mb->lock_mode == OP_MODE_1BY1) { bench_operation_1by1(os_mutex_lock_wrapper, os_mutex_unlock_wrapper, mb, NULL); } else { bench_operation_all_lock(os_mutex_lock_wrapper, os_mutex_unlock_wrapper, mb, NULL); } } return 0; } /* * init_bench_rwlock -- allocate and initialize rwlock objects */ static int init_bench_rwlock(struct mutex_bench *mb) { struct my_root *root = D_RW(mb->root); assert(root != NULL); POBJ_ZALLOC(mb->pop, &root->locks, lock_t, mb->pa->n_locks * sizeof(lock_t)); if (TOID_IS_NULL(root->locks)) { perror("POBJ_ZALLOC"); return -1; } mb->locks = D_RW(root->locks); assert(mb->locks != NULL); if (!mb->pa->use_system_threads) { /* initialize PMEM rwlocks */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { PMEMrwlock_internal *p = (PMEMrwlock_internal *)&mb->locks[i]; p->pmemrwlock.runid = mb->pa->runid_initial_value; os_rwlock_init(&p->PMEMrwlock_lock); } } else { /* initialize os_thread rwlocks */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { os_rwlock_t *p = (os_rwlock_t *)&mb->locks[i]; os_rwlock_init(p); } } return 0; } /* * exit_bench_rwlock -- destroy the rwlocks and release memory */ static int exit_bench_rwlock(struct mutex_bench *mb) { if (mb->pa->use_system_threads) { /* deinitialize os_thread mutex objects */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { os_rwlock_t *p = (os_rwlock_t *)&mb->locks[i]; os_rwlock_destroy(p); } } POBJ_FREE(&D_RW(mb->root)->locks); return 0; } /* * op_bench_rwlock -- lock and unlock the rwlock object * * If requested, increment the run_id of the memory pool. In case of PMEMrwlock * this will force the rwlock object(s) reinitialization at the lock operation. */ static int op_bench_rwlock(struct mutex_bench *mb) { if (!mb->pa->use_system_threads) { if (mb->lock_mode == OP_MODE_1BY1) { bench_operation_1by1( !mb->pa->use_rdlock ? pmemobj_rwlock_wrlock_wrapper : pmemobj_rwlock_rdlock_wrapper, pmemobj_rwlock_unlock_wrapper, mb, mb->pop); } else { bench_operation_all_lock( !mb->pa->use_rdlock ? pmemobj_rwlock_wrlock_wrapper : pmemobj_rwlock_rdlock_wrapper, pmemobj_rwlock_unlock_wrapper, mb, mb->pop); } if (mb->pa->run_id_increment) mb->pop->run_id += 2; /* must be a multiple of 2 */ } else { if (mb->lock_mode == OP_MODE_1BY1) { bench_operation_1by1( !mb->pa->use_rdlock ? os_rwlock_wrlock_wrapper : os_rwlock_rdlock_wrapper, os_rwlock_unlock_wrapper, mb, NULL); } else { bench_operation_all_lock( !mb->pa->use_rdlock ? os_rwlock_wrlock_wrapper : os_rwlock_rdlock_wrapper, os_rwlock_unlock_wrapper, mb, NULL); } } return 0; } /* * init_bench_vmutex -- allocate and initialize mutexes */ static int init_bench_vmutex(struct mutex_bench *mb) { struct my_root *root = D_RW(mb->root); assert(root != NULL); POBJ_ZALLOC(mb->pop, &root->locks, lock_t, mb->pa->n_locks * sizeof(lock_t)); if (TOID_IS_NULL(root->locks)) { perror("POBJ_ZALLOC"); return -1; } mb->locks = D_RW(root->locks); assert(mb->locks != NULL); /* initialize PMEM volatile mutexes */ for (unsigned i = 0; i < mb->pa->n_locks; i++) { PMEM_volatile_mutex *p = (PMEM_volatile_mutex *)&mb->locks[i]; p->volatile_pmemmutex.runid = mb->pa->runid_initial_value; volatile_mutex_init(&p->volatile_pmemmutex.mutexp, NULL); } return 0; } /* * exit_bench_vmutex -- destroy the mutex objects and release their * memory */ static int exit_bench_vmutex(struct mutex_bench *mb) { for (unsigned i = 0; i < mb->pa->n_locks; i++) { PMEM_volatile_mutex *p = (PMEM_volatile_mutex *)&mb->locks[i]; volatile_mutex_destroy(mb->pop, p); } POBJ_FREE(&D_RW(mb->root)->locks); return 0; } /* * op_bench_volatile_mutex -- lock and unlock the mutex object */ static int op_bench_vmutex(struct mutex_bench *mb) { if (mb->lock_mode == OP_MODE_1BY1) { bench_operation_1by1(volatile_mutex_lock_wrapper, volatile_mutex_unlock_wrapper, mb, mb->pop); } else { bench_operation_all_lock(volatile_mutex_lock_wrapper, volatile_mutex_unlock_wrapper, mb, mb->pop); } if (mb->pa->run_id_increment) mb->pop->run_id += 2; /* must be a multiple of 2 */ return 0; } struct bench_ops benchmark_ops[BENCH_MODE_MAX] = { {init_bench_mutex, exit_bench_mutex, op_bench_mutex}, {init_bench_rwlock, exit_bench_rwlock, op_bench_rwlock}, {init_bench_vmutex, exit_bench_vmutex, op_bench_vmutex}}; /* * operation_mode -- parses command line "--mode" and returns * proper operation mode */ static enum operation_mode parse_op_mode(const char *arg) { if (strcmp(arg, "1by1") == 0) return OP_MODE_1BY1; else if (strcmp(arg, "all-lock") == 0) return OP_MODE_ALL_LOCK; else return OP_MODE_MAX; } /* * benchmark_mode -- parses command line "--bench_type" and returns * proper benchmark ops */ static struct bench_ops * parse_benchmark_mode(const char *arg) { if (strcmp(arg, "mutex") == 0) return &benchmark_ops[BENCH_MODE_MUTEX]; else if (strcmp(arg, "rwlock") == 0) return &benchmark_ops[BENCH_MODE_RWLOCK]; else if (strcmp(arg, "volatile-mutex") == 0) return &benchmark_ops[BENCH_MODE_VOLATILE_MUTEX]; else return NULL; } /* * locks_init -- allocates persistent memory, maps it, creates the appropriate * objects in the allocated memory and initializes them */ static int locks_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); int ret = 0; size_t poolsize; struct mutex_bench *mb = (struct mutex_bench *)malloc(sizeof(*mb)); if (mb == NULL) { perror("malloc"); return -1; } mb->pa = (struct prog_args *)args->opts; mb->lock_mode = parse_op_mode(mb->pa->lock_mode); if (mb->lock_mode >= OP_MODE_MAX) { fprintf(stderr, "Invalid mutex mode: %s\n", mb->pa->lock_mode); errno = EINVAL; goto err_free_mb; } mb->ops = parse_benchmark_mode(mb->pa->lock_type); if (mb->ops == NULL) { fprintf(stderr, "Invalid benchmark type: %s\n", mb->pa->lock_type); errno = EINVAL; goto err_free_mb; } /* reserve some space for metadata */ poolsize = mb->pa->n_locks * sizeof(lock_t) + PMEMOBJ_MIN_POOL; if (args->is_poolset) { if (args->fsize < poolsize) { fprintf(stderr, "insufficient size of poolset\n"); goto err_free_mb; } poolsize = 0; } mb->pop = pmemobj_create(args->fname, POBJ_LAYOUT_NAME(pmembench_lock_layout), poolsize, args->fmode); if (mb->pop == NULL) { ret = -1; perror("pmemobj_create"); goto err_free_mb; } mb->root = POBJ_ROOT(mb->pop, struct my_root); assert(!TOID_IS_NULL(mb->root)); ret = mb->ops->bench_init(mb); if (ret != 0) goto err_free_pop; pmembench_set_priv(bench, mb); return 0; err_free_pop: pmemobj_close(mb->pop); err_free_mb: free(mb); return ret; } /* * locks_exit -- destroys allocated objects and release memory */ static int locks_exit(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); struct mutex_bench *mb = (struct mutex_bench *)pmembench_get_priv(bench); assert(mb != NULL); mb->ops->bench_exit(mb); pmemobj_close(mb->pop); free(mb); return 0; } /* * locks_op -- actual benchmark operation * * Performs lock and unlock as by the program arguments. */ static int locks_op(struct benchmark *bench, struct operation_info *info) { struct mutex_bench *mb = (struct mutex_bench *)pmembench_get_priv(bench); assert(mb != NULL); assert(mb->pop != NULL); assert(!TOID_IS_NULL(mb->root)); assert(mb->locks != NULL); assert(mb->lock_mode < OP_MODE_MAX); mb->ops->bench_op(mb); return 0; } /* structure to define command line arguments */ static struct benchmark_clo locks_clo[7]; static struct benchmark_info locks_info; CONSTRUCTOR(pmem_locks_costructor) void pmem_locks_costructor(void) { locks_clo[0].opt_short = 'p'; locks_clo[0].opt_long = "use_system_threads"; locks_clo[0].descr = "Use os_thread locks instead of PMEM, " "does not matter for volatile mutex"; locks_clo[0].def = "false"; locks_clo[0].off = clo_field_offset(struct prog_args, use_system_threads); locks_clo[0].type = CLO_TYPE_FLAG; locks_clo[1].opt_short = 'm'; locks_clo[1].opt_long = "numlocks"; locks_clo[1].descr = "The number of lock objects used " "for benchmark"; locks_clo[1].def = "1"; locks_clo[1].off = clo_field_offset(struct prog_args, n_locks); locks_clo[1].type = CLO_TYPE_UINT; locks_clo[1].type_uint.size = clo_field_size(struct prog_args, n_locks); locks_clo[1].type_uint.base = CLO_INT_BASE_DEC; locks_clo[1].type_uint.min = 1; locks_clo[1].type_uint.max = UINT_MAX; locks_clo[2].opt_short = 0; locks_clo[2].opt_long = "mode"; locks_clo[2].descr = "Locking mode"; locks_clo[2].type = CLO_TYPE_STR; locks_clo[2].off = clo_field_offset(struct prog_args, lock_mode); locks_clo[2].def = "1by1"; locks_clo[3].opt_short = 'r'; locks_clo[3].opt_long = "run_id"; locks_clo[3].descr = "Increment the run_id of PMEM object " "pool after each operation"; locks_clo[3].def = "false"; locks_clo[3].off = clo_field_offset(struct prog_args, run_id_increment); locks_clo[3].type = CLO_TYPE_FLAG; locks_clo[4].opt_short = 'i'; locks_clo[4].opt_long = "run_id_init_val"; locks_clo[4].descr = "Use this value for initializing the " "run_id of each PMEMmutex object"; locks_clo[4].def = "2"; locks_clo[4].off = clo_field_offset(struct prog_args, runid_initial_value); locks_clo[4].type = CLO_TYPE_UINT; locks_clo[4].type_uint.size = clo_field_size(struct prog_args, runid_initial_value); locks_clo[4].type_uint.base = CLO_INT_BASE_DEC; locks_clo[4].type_uint.min = 0; locks_clo[4].type_uint.max = UINT64_MAX; locks_clo[5].opt_short = 'b'; locks_clo[5].opt_long = "bench_type"; locks_clo[5].descr = "The Benchmark type: mutex, " "rwlock or volatile-mutex"; locks_clo[5].type = CLO_TYPE_STR; locks_clo[5].off = clo_field_offset(struct prog_args, lock_type); locks_clo[5].def = "mutex"; locks_clo[6].opt_short = 'R'; locks_clo[6].opt_long = "rdlock"; locks_clo[6].descr = "Select read over write lock, only " "valid when lock_type is \"rwlock\""; locks_clo[6].type = CLO_TYPE_FLAG; locks_clo[6].off = clo_field_offset(struct prog_args, use_rdlock); locks_info.name = "obj_locks"; locks_info.brief = "Benchmark for pmem locks operations"; locks_info.init = locks_init; locks_info.exit = locks_exit; locks_info.multithread = false; locks_info.multiops = true; locks_info.operation = locks_op; locks_info.measure_time = true; locks_info.clos = locks_clo; locks_info.nclos = ARRAY_SIZE(locks_clo); locks_info.opts_size = sizeof(struct prog_args); locks_info.rm_file = true; locks_info.allow_poolset = true; REGISTER_BENCHMARK(locks_info); }; pmdk-1.4.1/src/benchmarks/obj_pmalloc.cpp000066400000000000000000000335531331545616200203600ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * obj_pmalloc.cpp -- pmalloc benchmarks definition */ #include #include #include #include #include #include #include #include #include "benchmark.hpp" #include "libpmemobj.h" #include "os.h" #include "valgrind_internal.h" #ifdef __cplusplus extern "C" { #endif #include "memops.h" #include "pmalloc.h" #include "redo.h" #ifdef __cplusplus } #endif /* * The factor used for PMEM pool size calculation, accounts for metadata, * fragmentation and etc. */ #define FACTOR 1.2f /* The minimum allocation size that pmalloc can perform */ #define ALLOC_MIN_SIZE 64 /* OOB and allocation header size */ #define OOB_HEADER_SIZE 64 /* * prog_args - command line parsed arguments */ struct prog_args { size_t minsize; /* minimum size for random allocation size */ bool use_random_size; /* if set, use random size allocations */ unsigned seed; /* PRNG seed */ }; POBJ_LAYOUT_BEGIN(pmalloc_layout); POBJ_LAYOUT_ROOT(pmalloc_layout, struct my_root); POBJ_LAYOUT_TOID(pmalloc_layout, uint64_t); POBJ_LAYOUT_END(pmalloc_layout); /* * my_root - root object */ struct my_root { TOID(uint64_t) offs; /* vector of the allocated object offsets */ }; /* * obj_bench - variables used in benchmark, passed within functions */ struct obj_bench { PMEMobjpool *pop; /* persistent pool handle */ struct prog_args *pa; /* prog_args structure */ size_t *sizes; /* sizes for allocations */ TOID(struct my_root) root; /* root object's OID */ uint64_t *offs; /* pointer to the vector of offsets */ }; /* * obj_init -- common part of the benchmark initialization for pmalloc and * pfree. It allocates the PMEM memory pool and the necessary offset vector. */ static int obj_init(struct benchmark *bench, struct benchmark_args *args) { struct my_root *root = NULL; assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); if (((struct prog_args *)(args->opts))->minsize >= args->dsize) { fprintf(stderr, "Wrong params - allocation size\n"); return -1; } struct obj_bench *ob = (struct obj_bench *)malloc(sizeof(struct obj_bench)); if (ob == NULL) { perror("malloc"); return -1; } pmembench_set_priv(bench, ob); ob->pa = (struct prog_args *)args->opts; size_t n_ops_total = args->n_ops_per_thread * args->n_threads; assert(n_ops_total != 0); /* Create pmemobj pool. */ size_t alloc_size = args->dsize; if (alloc_size < ALLOC_MIN_SIZE) alloc_size = ALLOC_MIN_SIZE; /* For data objects */ size_t poolsize = PMEMOBJ_MIN_POOL + (n_ops_total * (alloc_size + OOB_HEADER_SIZE)) /* for offsets */ + n_ops_total * sizeof(uint64_t); /* multiply by FACTOR for metadata, fragmentation, etc. */ poolsize = (size_t)(poolsize * FACTOR); if (args->is_poolset) { if (args->fsize < poolsize) { fprintf(stderr, "insufficient size of poolset\n"); goto free_ob; } poolsize = 0; } else { if (poolsize < PMEMOBJ_MIN_POOL) poolsize = PMEMOBJ_MIN_POOL; } ob->pop = pmemobj_create(args->fname, POBJ_LAYOUT_NAME(pmalloc_layout), poolsize, args->fmode); if (ob->pop == NULL) { fprintf(stderr, "%s\n", pmemobj_errormsg()); goto free_ob; } ob->root = POBJ_ROOT(ob->pop, struct my_root); if (TOID_IS_NULL(ob->root)) { fprintf(stderr, "POBJ_ROOT: %s\n", pmemobj_errormsg()); goto free_pop; } root = D_RW(ob->root); assert(root != NULL); POBJ_ZALLOC(ob->pop, &root->offs, uint64_t, n_ops_total * sizeof(PMEMoid)); if (TOID_IS_NULL(root->offs)) { fprintf(stderr, "POBJ_ZALLOC off_vect: %s\n", pmemobj_errormsg()); goto free_pop; } ob->offs = D_RW(root->offs); ob->sizes = (size_t *)malloc(n_ops_total * sizeof(size_t)); if (ob->sizes == NULL) { fprintf(stderr, "malloc rand size vect err\n"); goto free_pop; } if (ob->pa->use_random_size) { size_t width = args->dsize - ob->pa->minsize; for (size_t i = 0; i < n_ops_total; i++) { uint32_t hr = (uint32_t)os_rand_r(&ob->pa->seed); uint32_t lr = (uint32_t)os_rand_r(&ob->pa->seed); uint64_t r64 = (uint64_t)hr << 32 | lr; ob->sizes[i] = r64 % width + ob->pa->minsize; } } else { for (size_t i = 0; i < n_ops_total; i++) ob->sizes[i] = args->dsize; } return 0; free_pop: pmemobj_close(ob->pop); free_ob: free(ob); return -1; } /* * obj_exit -- common part for the exit function for pmalloc and pfree * benchmarks. It frees the allocated offset vector and the memory pool. */ static int obj_exit(struct benchmark *bench, struct benchmark_args *args) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); free(ob->sizes); POBJ_FREE(&D_RW(ob->root)->offs); pmemobj_close(ob->pop); return 0; } /* * pmalloc_init -- initialization for the pmalloc benchmark. Performs only the * common initialization. */ static int pmalloc_init(struct benchmark *bench, struct benchmark_args *args) { return obj_init(bench, args); } /* * pmalloc_op -- actual benchmark operation. Performs the pmalloc allocations. */ static int pmalloc_op(struct benchmark *bench, struct operation_info *info) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); uint64_t i = info->index + info->worker->index * info->args->n_ops_per_thread; int ret = pmalloc(ob->pop, &ob->offs[i], ob->sizes[i], 0, 0); if (ret) { fprintf(stderr, "pmalloc ret: %d\n", ret); return ret; } return 0; } struct pmix_worker { size_t nobjects; size_t shuffle_start; unsigned seed; }; /* * pmix_worker_init -- initialization of the worker structure */ static int pmix_worker_init(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); struct pmix_worker *w = (struct pmix_worker *)calloc(1, sizeof(*w)); if (w == NULL) return -1; w->seed = ob->pa->seed; worker->priv = w; return 0; } /* * pmix_worker_fini -- destruction of the worker structure */ static void pmix_worker_fini(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct pmix_worker *w = (struct pmix_worker *)worker->priv; free(w); } /* * shuffle_objects -- randomly shuffle elements on a list * * Ideally, we wouldn't count the time this function takes, but for all * practial purposes this is fast enough and isn't visible on the results. * Just make sure the amount of objects to shuffle is not large. */ static void shuffle_objects(uint64_t *objects, size_t start, size_t nobjects, unsigned *seed) { uint64_t tmp; size_t dest; for (size_t n = start; n < nobjects; ++n) { dest = RRAND_R(seed, nobjects - 1, 0); tmp = objects[n]; objects[n] = objects[dest]; objects[dest] = tmp; } } #define FREE_PCT 10 #define FREE_OPS 10 /* * pmix_op -- mixed workload benchmark */ static int pmix_op(struct benchmark *bench, struct operation_info *info) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); struct pmix_worker *w = (struct pmix_worker *)info->worker->priv; uint64_t idx = info->worker->index * info->args->n_ops_per_thread; uint64_t *objects = &ob->offs[idx]; if (w->nobjects > FREE_OPS && FREE_PCT > RRAND_R(&w->seed, 100, 0)) { shuffle_objects(objects, w->shuffle_start, w->nobjects, &w->seed); for (int i = 0; i < FREE_OPS; ++i) { uint64_t off = objects[--w->nobjects]; pfree(ob->pop, &off); } w->shuffle_start = w->nobjects; } else { int ret = pmalloc(ob->pop, &objects[w->nobjects++], ob->sizes[idx + info->index], 0, 0); if (ret) { fprintf(stderr, "pmalloc ret: %d\n", ret); return ret; } } return 0; } /* * pmalloc_exit -- the end of the pmalloc benchmark. Frees the memory allocated * during pmalloc_op and performs the common exit operations. */ static int pmalloc_exit(struct benchmark *bench, struct benchmark_args *args) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); for (size_t i = 0; i < args->n_ops_per_thread * args->n_threads; i++) { if (ob->offs[i]) pfree(ob->pop, &ob->offs[i]); } return obj_exit(bench, args); } /* * pfree_init -- initialization for the pfree benchmark. Performs the common * initialization and allocates the memory to be freed during pfree_op. */ static int pfree_init(struct benchmark *bench, struct benchmark_args *args) { int ret = obj_init(bench, args); if (ret) return ret; struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); for (size_t i = 0; i < args->n_ops_per_thread * args->n_threads; i++) { ret = pmalloc(ob->pop, &ob->offs[i], ob->sizes[i], 0, 0); if (ret) { fprintf(stderr, "pmalloc at idx %" PRIu64 " ret: %s\n", i, pmemobj_errormsg()); /* free the allocated memory */ while (i != 0) { pfree(ob->pop, &ob->offs[i - 1]); i--; } obj_exit(bench, args); return ret; } } return 0; } /* * pmalloc_op -- actual benchmark operation. Performs the pfree operation. */ static int pfree_op(struct benchmark *bench, struct operation_info *info) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); uint64_t i = info->index + info->worker->index * info->args->n_ops_per_thread; pfree(ob->pop, &ob->offs[i]); return 0; } /* command line options definition */ static struct benchmark_clo pmalloc_clo[3]; /* * Stores information about pmalloc benchmark. */ static struct benchmark_info pmalloc_info; /* * Stores information about pfree benchmark. */ static struct benchmark_info pfree_info; /* * Stores information about pmix benchmark. */ static struct benchmark_info pmix_info; CONSTRUCTOR(obj_pmalloc_costructor) void obj_pmalloc_costructor(void) { pmalloc_clo[0].opt_short = 'r'; pmalloc_clo[0].opt_long = "random"; pmalloc_clo[0].descr = "Use random size allocations - " "from min-size to data-size"; pmalloc_clo[0].off = clo_field_offset(struct prog_args, use_random_size); pmalloc_clo[0].type = CLO_TYPE_FLAG; pmalloc_clo[1].opt_short = 'm'; pmalloc_clo[1].opt_long = "min-size"; pmalloc_clo[1].descr = "Minimum size of allocation for " "random mode"; pmalloc_clo[1].type = CLO_TYPE_UINT; pmalloc_clo[1].off = clo_field_offset(struct prog_args, minsize); pmalloc_clo[1].def = "1"; pmalloc_clo[1].type_uint.size = clo_field_size(struct prog_args, minsize); pmalloc_clo[1].type_uint.base = CLO_INT_BASE_DEC; pmalloc_clo[1].type_uint.min = 1; pmalloc_clo[1].type_uint.max = UINT64_MAX; pmalloc_clo[2].opt_short = 'S'; pmalloc_clo[2].opt_long = "seed"; pmalloc_clo[2].descr = "Random mode seed value"; pmalloc_clo[2].off = clo_field_offset(struct prog_args, seed); pmalloc_clo[2].def = "1"; pmalloc_clo[2].type = CLO_TYPE_UINT; pmalloc_clo[2].type_uint.size = clo_field_size(struct prog_args, seed); pmalloc_clo[2].type_uint.base = CLO_INT_BASE_DEC; pmalloc_clo[2].type_uint.min = 1; pmalloc_clo[2].type_uint.max = UINT_MAX; pmalloc_info.name = "pmalloc", pmalloc_info.brief = "Benchmark for internal pmalloc() " "operation"; pmalloc_info.init = pmalloc_init; pmalloc_info.exit = pmalloc_exit; pmalloc_info.multithread = true; pmalloc_info.multiops = true; pmalloc_info.operation = pmalloc_op; pmalloc_info.measure_time = true; pmalloc_info.clos = pmalloc_clo; pmalloc_info.nclos = ARRAY_SIZE(pmalloc_clo); pmalloc_info.opts_size = sizeof(struct prog_args); pmalloc_info.rm_file = true; pmalloc_info.allow_poolset = true; REGISTER_BENCHMARK(pmalloc_info); pfree_info.name = "pfree"; pfree_info.brief = "Benchmark for internal pfree() " "operation"; pfree_info.init = pfree_init; pfree_info.exit = pmalloc_exit; /* same as for pmalloc */ pfree_info.multithread = true; pfree_info.multiops = true; pfree_info.operation = pfree_op; pfree_info.measure_time = true; pfree_info.clos = pmalloc_clo; pfree_info.nclos = ARRAY_SIZE(pmalloc_clo); pfree_info.opts_size = sizeof(struct prog_args); pfree_info.rm_file = true; pfree_info.allow_poolset = true; REGISTER_BENCHMARK(pfree_info); pmix_info.name = "pmix"; pmix_info.brief = "Benchmark for mixed alloc/free workload"; pmix_info.init = pmalloc_init; pmix_info.exit = pmalloc_exit; /* same as for pmalloc */ pmix_info.multithread = true; pmix_info.multiops = true; pmix_info.operation = pmix_op; pmix_info.init_worker = pmix_worker_init; pmix_info.free_worker = pmix_worker_fini; pmix_info.measure_time = true; pmix_info.clos = pmalloc_clo; pmix_info.nclos = ARRAY_SIZE(pmalloc_clo); pmix_info.opts_size = sizeof(struct prog_args); pmix_info.rm_file = true; pmix_info.allow_poolset = true; REGISTER_BENCHMARK(pmix_info); }; pmdk-1.4.1/src/benchmarks/perf.cfg000066400000000000000000000045471331545616200170110ustar00rootroot00000000000000[global] file = testfile repeats = 3 # pmemobj_tx_alloc(size = 256) vs threads [obj_tx_alloc_small_v_thread] bench = obj_tx_alloc group = pmemobj ops-per-thread = 200000 threads = 1:+1:32 type-number = per-thread data-size = 256 # pmemobj_tx_alloc(size = 128k) vs threads [obj_tx_alloc_huge_v_threads] bench = obj_tx_alloc group = pmemobj ops-per-thread = 11000 threads = 1:+1:32 type-number = per-thread data-size = 131072 # pmemobj_tx_alloc vs data-size [obj_tx_alloc_v_data_size] bench = obj_tx_alloc group = pmemobj ops-per-thread = 50000 threads = 1 type-number = one data-size = 64:*2:32768 # pmalloc (size = 100) vs threads [obj_pmalloc_small_v_threads] bench = pmalloc group = pmemobj ops-per-thread = 200000 threads = 1:+1:32 data-size = 100 # pmalloc (size = 128k) vs threads [obj_pmalloc_huge_v_threads] bench = pmalloc group = pmemobj ops-per-thread = 11000 threads = 1:+1:32 data-size = 131072 # pmalloc vs data-size [obj_pmalloc_v_data_size] bench = pmalloc group = pmemobj ops-per-thread = 50000 threads = 1 data-size = 64:*2:32768 # btree_map_insert [obj_btree_map_insert] bench = map_insert group = pmemobj ops-per-thread = 5000000 type = btree threads = 1 # ctree_map_insert [obj_ctree_map_insert] bench = map_insert group = pmemobj ops-per-thread = 5000000 type = ctree threads = 1 # rtree_map_insert [obj_rtree_map_insert] bench = map_insert group = pmemobj ops-per-thread = 1000000 type = rtree threads = 1 # rbtree_map_insert [obj_rbtree_map_insert] bench = map_insert group = pmemobj ops-per-thread = 5000000 type = rbtree threads = 1 # hashmap_tx_map_insert [obj_hashmap_tx_map_insert] bench = map_insert group = pmemobj ops-per-thread = 5000000 type = hashmap_tx threads = 1 # hashmap_atomic_map_insert [obj_hashmap_atomic_map_insert] bench = map_insert group = pmemobj ops-per-thread = 5000000 type = hashmap_atomic threads = 1 # pmemblk_write(size = 512, random) vs threads [blk_write_v_threads] bench = blk_write group = pmemblk file-size = 1073741824 ops-per-thread = 1000000 threads = 1:+1:32 data-size = 512 mode = rand # pmemblk_read(size = 512, random) vs threads [blk_read_v_threads] bench = blk_read group = pmemblk file-size = 1073741824 ops-per-thread = 1000000 threads = 1:+1:32 data-size = 512 mode = rand # log_append vs data-size [log_append_v_data_size] bench = log_append group = pmemlog ops-per-thread = 1000000 threads = 1 data-size = 32:*2:32768 pmdk-1.4.1/src/benchmarks/pmem_flush.cpp000066400000000000000000000340551331545616200202340ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmem_flush.cpp -- benchmark implementation for pmem_persist and pmem_msync */ #include #include #include #include #include #include #include #include #include #include #include "benchmark.hpp" #define PAGE_4K ((uintptr_t)1 << 12) #define PAGE_2M ((uintptr_t)1 << 21) /* * align_addr -- round addr down to given boundary */ static void * align_addr(void *addr, uintptr_t align) { return (char *)((uintptr_t)addr & ~(align - 1)); } /* * align_len -- increase len by the amount we gain when we round addr down */ static size_t align_len(size_t len, void *addr, uintptr_t align) { return len + ((uintptr_t)addr & (align - 1)); } /* * roundup_len -- increase len by the amount we gain when we round addr down, * then round up to the nearest multiple of 4K */ static size_t roundup_len(size_t len, void *addr, uintptr_t align) { return (align_len(len, addr, align) + align - 1) & ~(align - 1); } /* * pmem_args -- benchmark specific arguments */ struct pmem_args { char *operation; /* msync, dummy_msync, persist, ... */ char *mode; /* stat, seq, rand */ bool no_warmup; /* don't do warmup */ }; /* * pmem_bench -- benchmark context */ struct pmem_bench { uint64_t *offsets; /* write offsets */ size_t n_offsets; /* number of elements in offsets array */ size_t fsize; /* The size of the allocated PMEM */ struct pmem_args *pargs; /* prog_args structure */ void *pmem_addr; /* PMEM base address */ size_t pmem_len; /* length of PMEM mapping */ void *invalid_addr; /* invalid pages */ void *nondirty_addr; /* non-dirty pages */ void *pmem_addr_aligned; /* PMEM pages - 2M aligned */ void *invalid_addr_aligned; /* invalid pages - 2M aligned */ void *nondirty_addr_aligned; /* non-dirty pages - 2M aligned */ /* the actual benchmark operation */ int (*func_op)(struct pmem_bench *pmb, void *addr, size_t len); }; /* * mode_seq -- if copy mode is sequential, returns index of a chunk. */ static uint64_t mode_seq(struct pmem_bench *pmb, uint64_t index) { return index; } /* * mode_stat -- if mode is static, the offset is always 0 */ static uint64_t mode_stat(struct pmem_bench *pmb, uint64_t index) { return 0; } /* * mode_rand -- if mode is random, returns index of a random chunk */ static uint64_t mode_rand(struct pmem_bench *pmb, uint64_t index) { return rand() % pmb->n_offsets; } /* * operation_mode -- the mode of the copy process * * * static - write always the same chunk, * * sequential - write chunk by chunk, * * random - write to chunks selected randomly. */ struct op_mode { const char *mode; uint64_t (*func_mode)(struct pmem_bench *pmb, uint64_t index); }; static struct op_mode modes[] = { {"stat", mode_stat}, {"seq", mode_seq}, {"rand", mode_rand}, }; #define MODES (sizeof(modes) / sizeof(modes[0])) /* * parse_op_mode -- parses command line "--mode" * and returns proper operation mode index. */ static int parse_op_mode(const char *arg) { for (unsigned i = 0; i < MODES; i++) { if (strcmp(arg, modes[i].mode) == 0) return i; } return -1; } /* * flush_noop -- dummy flush, does nothing */ static int flush_noop(struct pmem_bench *pmb, void *addr, size_t len) { return 0; } /* * flush_persist -- flush data to persistence using pmem_persist() */ static int flush_persist(struct pmem_bench *pmb, void *addr, size_t len) { pmem_persist(addr, len); return 0; } /* * flush_persist_4K -- always flush entire 4K page(s) using pmem_persist() */ static int flush_persist_4K(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_4K); len = roundup_len(len, addr, PAGE_4K); pmem_persist(ptr, len); return 0; } /* * flush_persist_2M -- always flush entire 2M page(s) using pmem_persist() */ static int flush_persist_2M(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_2M); len = roundup_len(len, addr, PAGE_2M); pmem_persist(ptr, len); return 0; } /* * flush_msync -- flush data to persistence using pmem_msync() */ static int flush_msync(struct pmem_bench *pmb, void *addr, size_t len) { pmem_msync(addr, len); return 0; } /* * flush_msync_async -- emulate dummy msync() using MS_ASYNC flag */ static int flush_msync_async(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_4K); len = align_len(len, addr, PAGE_4K); msync(ptr, len, MS_ASYNC); return 0; } /* * flush_msync_0 -- emulate dummy msync() using zero length */ static int flush_msync_0(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_4K); (void)len; msync(ptr, 0, MS_SYNC); return 0; } /* * flush_persist_4K_msync_0 -- emulate msync() that only flushes CPU cache * * Do flushing in user space (4K pages) + dummy syscall. */ static int flush_persist_4K_msync_0(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_4K); len = roundup_len(len, addr, PAGE_4K); pmem_persist(ptr, len); msync(ptr, 0, MS_SYNC); return 0; } /* * flush_persist_2M_msync_0 -- emulate msync() that only flushes CPU cache * * Do flushing in user space (2M pages) + dummy syscall. */ static int flush_persist_2M_msync_0(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_2M); len = roundup_len(len, addr, PAGE_2M); pmem_persist(ptr, len); msync(ptr, 0, MS_SYNC); return 0; } /* * flush_msync_err -- emulate dummy msync() using invalid flags */ static int flush_msync_err(struct pmem_bench *pmb, void *addr, size_t len) { void *ptr = align_addr(addr, PAGE_4K); len = align_len(len, addr, PAGE_4K); msync(ptr, len, MS_SYNC | MS_ASYNC); return 0; } /* * flush_msync_nodirty -- call msync() on non-dirty pages */ static int flush_msync_nodirty(struct pmem_bench *pmb, void *addr, size_t len) { uintptr_t uptr = (uintptr_t)addr - (uintptr_t)pmb->pmem_addr_aligned; uptr += (uintptr_t)pmb->nondirty_addr_aligned; void *ptr = align_addr((void *)uptr, PAGE_4K); len = align_len(len, (void *)uptr, PAGE_4K); pmem_msync(ptr, len); return 0; } /* * flush_msync_invalid -- emulate dummy msync() using invalid address */ static int flush_msync_invalid(struct pmem_bench *pmb, void *addr, size_t len) { uintptr_t uptr = (uintptr_t)addr - (uintptr_t)pmb->pmem_addr_aligned; uptr += (uintptr_t)pmb->invalid_addr_aligned; void *ptr = align_addr((void *)uptr, PAGE_4K); len = align_len(len, (void *)uptr, PAGE_4K); pmem_msync(ptr, len); return 0; } struct op { const char *opname; int (*func_op)(struct pmem_bench *pmb, void *addr, size_t len); }; static struct op ops[] = { {"noop", flush_noop}, {"persist", flush_persist}, {"persist_4K", flush_persist_4K}, {"persist_2M", flush_persist_2M}, {"msync", flush_msync}, {"msync_0", flush_msync_0}, {"msync_err", flush_msync_err}, {"persist_4K_msync_0", flush_persist_4K_msync_0}, {"persist_2M_msync_0", flush_persist_2M_msync_0}, {"msync_async", flush_msync_async}, {"msync_nodirty", flush_msync_nodirty}, {"msync_invalid", flush_msync_invalid}, }; #define NOPS (sizeof(ops) / sizeof(ops[0])) /* * parse_op_type -- parses command line "--operation" argument * and returns proper operation type. */ static int parse_op_type(const char *arg) { for (unsigned i = 0; i < NOPS; i++) { if (strcmp(arg, ops[i].opname) == 0) return i; } return -1; } /* * pmem_flush_init -- benchmark initialization * * Parses command line arguments, allocates persistent memory, and maps it. */ static int pmem_flush_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); uint64_t (*func_mode)(struct pmem_bench * pmb, uint64_t index); struct pmem_bench *pmb = (struct pmem_bench *)malloc(sizeof(struct pmem_bench)); assert(pmb != NULL); pmb->pargs = (struct pmem_args *)args->opts; assert(pmb->pargs != NULL); int i = parse_op_type(pmb->pargs->operation); if (i == -1) { fprintf(stderr, "wrong operation: %s\n", pmb->pargs->operation); goto err_free_pmb; } pmb->func_op = ops[i].func_op; pmb->n_offsets = args->n_ops_per_thread * args->n_threads; pmb->fsize = pmb->n_offsets * args->dsize + (2 * PAGE_2M); /* round up to 2M boundary */ pmb->fsize = (pmb->fsize + PAGE_2M - 1) & ~(PAGE_2M - 1); i = parse_op_mode(pmb->pargs->mode); if (i == -1) { fprintf(stderr, "wrong mode: %s\n", pmb->pargs->mode); goto err_free_pmb; } func_mode = modes[i].func_mode; /* populate offsets array */ assert(pmb->n_offsets != 0); pmb->offsets = (size_t *)malloc(pmb->n_offsets * sizeof(*pmb->offsets)); assert(pmb->offsets != NULL); for (size_t i = 0; i < pmb->n_offsets; ++i) pmb->offsets[i] = func_mode(pmb, i); /* create a pmem file and memory map it */ pmb->pmem_addr = pmem_map_file(args->fname, pmb->fsize, PMEM_FILE_CREATE | PMEM_FILE_EXCL, args->fmode, &pmb->pmem_len, NULL); if (pmb->pmem_addr == NULL) { perror("pmem_map_file"); goto err_free_pmb; } pmb->nondirty_addr = mmap(NULL, pmb->fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pmb->nondirty_addr == MAP_FAILED) { perror("mmap(1)"); goto err_unmap1; } pmb->invalid_addr = mmap(NULL, pmb->fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pmb->invalid_addr == MAP_FAILED) { perror("mmap(2)"); goto err_unmap2; } munmap(pmb->invalid_addr, pmb->fsize); pmb->pmem_addr_aligned = (void *)(((uintptr_t)pmb->pmem_addr + PAGE_2M - 1) & ~(PAGE_2M - 1)); pmb->nondirty_addr_aligned = (void *)(((uintptr_t)pmb->nondirty_addr + PAGE_2M - 1) & ~(PAGE_2M - 1)); pmb->invalid_addr_aligned = (void *)(((uintptr_t)pmb->invalid_addr + PAGE_2M - 1) & ~(PAGE_2M - 1)); pmembench_set_priv(bench, pmb); if (!pmb->pargs->no_warmup) { size_t off; for (off = 0; off < pmb->fsize - PAGE_2M; off += PAGE_4K) { *(int *)((char *)pmb->pmem_addr_aligned + off) = 0; *(int *)((char *)pmb->nondirty_addr_aligned + off) = 0; } } return 0; err_unmap2: munmap(pmb->nondirty_addr, pmb->fsize); err_unmap1: pmem_unmap(pmb->pmem_addr, pmb->pmem_len); err_free_pmb: free(pmb); return -1; } /* * pmem_flush_exit -- benchmark cleanup */ static int pmem_flush_exit(struct benchmark *bench, struct benchmark_args *args) { struct pmem_bench *pmb = (struct pmem_bench *)pmembench_get_priv(bench); pmem_unmap(pmb->pmem_addr, pmb->pmem_len); munmap(pmb->nondirty_addr, pmb->pmem_len); free(pmb); return 0; } /* * pmem_flush_operation -- actual benchmark operation */ static int pmem_flush_operation(struct benchmark *bench, struct operation_info *info) { struct pmem_bench *pmb = (struct pmem_bench *)pmembench_get_priv(bench); size_t op_idx = info->index; assert(op_idx < pmb->n_offsets); uint64_t chunk_idx = pmb->offsets[op_idx]; void *addr = (char *)pmb->pmem_addr_aligned + chunk_idx * info->args->dsize; /* store + flush */ *(int *)addr = *(int *)addr + 1; pmb->func_op(pmb, addr, info->args->dsize); return 0; } /* structure to define command line arguments */ static struct benchmark_clo pmem_flush_clo[3]; /* Stores information about benchmark. */ static struct benchmark_info pmem_flush_bench; CONSTRUCTOR(pmem_flush_costructor) void pmem_flush_costructor(void) { pmem_flush_clo[0].opt_short = 'o'; pmem_flush_clo[0].opt_long = "operation"; pmem_flush_clo[0].descr = "Operation type - persist," " msync, ..."; pmem_flush_clo[0].type = CLO_TYPE_STR; pmem_flush_clo[0].off = clo_field_offset(struct pmem_args, operation); pmem_flush_clo[0].def = "noop"; pmem_flush_clo[1].opt_short = 0; pmem_flush_clo[1].opt_long = "mode"; pmem_flush_clo[1].descr = "mode - stat, seq or rand"; pmem_flush_clo[1].type = CLO_TYPE_STR; pmem_flush_clo[1].off = clo_field_offset(struct pmem_args, mode); pmem_flush_clo[1].def = "stat"; pmem_flush_clo[2].opt_short = 'w'; pmem_flush_clo[2].opt_long = "no-warmup"; pmem_flush_clo[2].descr = "Don't do warmup"; pmem_flush_clo[2].type = CLO_TYPE_FLAG; pmem_flush_clo[2].off = clo_field_offset(struct pmem_args, no_warmup); pmem_flush_bench.name = "pmem_flush"; pmem_flush_bench.brief = "Benchmark for pmem_msync() " "and pmem_persist()"; pmem_flush_bench.init = pmem_flush_init; pmem_flush_bench.exit = pmem_flush_exit; pmem_flush_bench.multithread = true; pmem_flush_bench.multiops = true; pmem_flush_bench.operation = pmem_flush_operation; pmem_flush_bench.measure_time = true; pmem_flush_bench.clos = pmem_flush_clo; pmem_flush_bench.nclos = ARRAY_SIZE(pmem_flush_clo); pmem_flush_bench.opts_size = sizeof(struct pmem_args); pmem_flush_bench.rm_file = true; pmem_flush_bench.allow_poolset = false; REGISTER_BENCHMARK(pmem_flush_bench); } pmdk-1.4.1/src/benchmarks/pmem_memcpy.cpp000066400000000000000000000373341331545616200204100ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmem_memcpy.cpp -- benchmark implementation for pmem_memcpy */ #include #include #include #include #include #include #include #include #include #include #include "benchmark.hpp" #define FLUSH_ALIGN 64 #define MAX_OFFSET (FLUSH_ALIGN - 1) struct pmem_bench; typedef size_t (*offset_fn)(struct pmem_bench *pmb, uint64_t index); /* * pmem_args -- benchmark specific arguments */ struct pmem_args { /* * Defines the copy operation direction. Whether it is * writing from RAM to PMEM (for argument value "write") * or PMEM to RAM (for argument value "read"). */ char *operation; /* * The source address offset used to test pmem_memcpy() * performance when source address is not aligned. */ size_t src_off; /* * The destination address offset used to test * pmem_memcpy() performance when destination address * is not aligned. */ size_t dest_off; /* The size of data chunk. */ size_t chunk_size; /* * Specifies the order in which data chunks are selected * to be copied. There are three modes supported: * stat, seq, rand. */ char *src_mode; /* * Specifies the order in which data chunks are written * to the destination address. There are three modes * supported: stat, seq, rand. */ char *dest_mode; /* * When this flag is set to true, PMEM is not used. * This option is useful, when comparing performance * of pmem_memcpy() function to regular memcpy(). */ bool memcpy; /* * When this flag is set to true, pmem_persist() * function is used, otherwise pmem_flush() is performed. */ bool persist; }; /* * pmem_bench -- benchmark context */ struct pmem_bench { /* random offsets */ unsigned *rand_offsets; /* number of elements in randoms array */ size_t n_rand_offsets; /* The size of the allocated PMEM */ size_t fsize; /* The size of the allocated buffer */ size_t bsize; /* Pointer to the allocated volatile memory */ unsigned char *buf; /* Pointer to the allocated PMEM */ unsigned char *pmem_addr; /* * This field gets 'buf' or 'pmem_addr' fields assigned, * depending on the prog_args operation direction. */ unsigned char *src_addr; /* * This field gets 'buf' or 'pmem_addr' fields assigned, * depending on the prog_args operation direction. */ unsigned char *dest_addr; /* Stores prog_args structure */ struct pmem_args *pargs; /* * Function which returns src offset. Matches src_mode. */ offset_fn func_src; /* * Function which returns dst offset. Matches dst_mode. */ offset_fn func_dest; /* * The actual operation performed based on benchmark specific * arguments. */ int (*func_op)(void *dest, void *source, size_t len); }; /* * operation_type -- type of operation relative to persistent memory */ enum operation_type { OP_TYPE_UNKNOWN, OP_TYPE_READ, OP_TYPE_WRITE }; /* * operation_mode -- the mode of the copy process * * * static - read/write always the same chunk, * * sequential - read/write chunk by chunk, * * random - read/write to chunks selected randomly. * * It is used to determine source mode as well as the destination mode. */ enum operation_mode { OP_MODE_UNKNOWN, OP_MODE_STAT, OP_MODE_SEQ, OP_MODE_RAND }; /* * parse_op_type -- parses command line "--operation" argument * and returns proper operation type. */ static enum operation_type parse_op_type(const char *arg) { if (strcmp(arg, "read") == 0) return OP_TYPE_READ; else if (strcmp(arg, "write") == 0) return OP_TYPE_WRITE; else return OP_TYPE_UNKNOWN; } /* * parse_op_mode -- parses command line "--src-mode" or "--dest-mode" * and returns proper operation mode. */ static enum operation_mode parse_op_mode(const char *arg) { if (strcmp(arg, "stat") == 0) return OP_MODE_STAT; else if (strcmp(arg, "seq") == 0) return OP_MODE_SEQ; else if (strcmp(arg, "rand") == 0) return OP_MODE_RAND; else return OP_MODE_UNKNOWN; } /* * mode_seq -- if copy mode is sequential mode_seq() returns * index of a chunk. */ static uint64_t mode_seq(struct pmem_bench *pmb, uint64_t index) { return index; } /* * mode_stat -- if mode is static, the offset is always 0, * as only one block is used. */ static uint64_t mode_stat(struct pmem_bench *pmb, uint64_t index) { return 0; } /* * mode_rand -- if mode is random returns index of a random chunk */ static uint64_t mode_rand(struct pmem_bench *pmb, uint64_t index) { assert(index < pmb->n_rand_offsets); return pmb->rand_offsets[index]; } /* * assign_mode_func -- parses "--src-mode" and "--dest-mode" command line * arguments and returns one of the above mode functions. */ static offset_fn assign_mode_func(char *option) { enum operation_mode op_mode = parse_op_mode(option); switch (op_mode) { case OP_MODE_STAT: return mode_stat; case OP_MODE_SEQ: return mode_seq; case OP_MODE_RAND: return mode_rand; default: return NULL; } } /* * libc_memcpy -- copy using libc memcpy() function * followed by pmem_flush(). */ static int libc_memcpy(void *dest, void *source, size_t len) { memcpy(dest, source, len); pmem_flush(dest, len); return 0; } /* * libc_memcpy_persist -- copy using libc memcpy() function * followed by pmem_persist(). */ static int libc_memcpy_persist(void *dest, void *source, size_t len) { memcpy(dest, source, len); pmem_persist(dest, len); return 0; } /* * lipmem_memcpy_nodrain -- copy using libpmem pmem_memcpy_no_drain() * function without pmem_persist(). */ static int libpmem_memcpy_nodrain(void *dest, void *source, size_t len) { pmem_memcpy_nodrain(dest, source, len); return 0; } /* * libpmem_memcpy_persist -- copy using libpmem pmem_memcpy_persist() function. */ static int libpmem_memcpy_persist(void *dest, void *source, size_t len) { pmem_memcpy_persist(dest, source, len); return 0; } /* * assign_size -- assigns file and buffer size * depending on the operation mode and type. */ static int assign_size(struct pmem_bench *pmb, struct benchmark_args *args, enum operation_type *op_type) { *op_type = parse_op_type(pmb->pargs->operation); if (*op_type == OP_TYPE_UNKNOWN) { fprintf(stderr, "Invalid operation argument '%s'", pmb->pargs->operation); return -1; } enum operation_mode op_mode_src = parse_op_mode(pmb->pargs->src_mode); if (op_mode_src == OP_MODE_UNKNOWN) { fprintf(stderr, "Invalid source mode argument '%s'", pmb->pargs->src_mode); return -1; } enum operation_mode op_mode_dest = parse_op_mode(pmb->pargs->dest_mode); if (op_mode_dest == OP_MODE_UNKNOWN) { fprintf(stderr, "Invalid destination mode argument '%s'", pmb->pargs->dest_mode); return -1; } size_t large = args->n_ops_per_thread * pmb->pargs->chunk_size * args->n_threads; size_t little = pmb->pargs->chunk_size; if (*op_type == OP_TYPE_WRITE) { pmb->bsize = op_mode_src == OP_MODE_STAT ? little : large; pmb->fsize = op_mode_dest == OP_MODE_STAT ? little : large; if (pmb->pargs->src_off != 0) pmb->bsize += MAX_OFFSET; if (pmb->pargs->dest_off != 0) pmb->fsize += MAX_OFFSET; } else { pmb->fsize = op_mode_src == OP_MODE_STAT ? little : large; pmb->bsize = op_mode_dest == OP_MODE_STAT ? little : large; if (pmb->pargs->src_off != 0) pmb->fsize += MAX_OFFSET; if (pmb->pargs->dest_off != 0) pmb->bsize += MAX_OFFSET; } return 0; } /* * pmem_memcpy_init -- benchmark initialization * * Parses command line arguments, allocates persistent memory, and maps it. */ static int pmem_memcpy_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); int ret = 0; struct pmem_bench *pmb = (struct pmem_bench *)malloc(sizeof(struct pmem_bench)); assert(pmb != NULL); pmb->pargs = (struct pmem_args *)args->opts; assert(pmb->pargs != NULL); pmb->pargs->chunk_size = args->dsize; enum operation_type op_type; /* * Assign file and buffer size depending on the operation type * (READ from PMEM or WRITE to PMEM) */ if (assign_size(pmb, args, &op_type) != 0) { ret = -1; goto err_free_pmb; } pmb->buf = (unsigned char *)util_aligned_malloc(FLUSH_ALIGN, pmb->bsize); if (pmb->buf == NULL) { perror("posix_memalign"); ret = -1; goto err_free_pmb; } pmb->n_rand_offsets = args->n_ops_per_thread * args->n_threads; assert(pmb->n_rand_offsets != 0); pmb->rand_offsets = (unsigned *)malloc(pmb->n_rand_offsets * sizeof(*pmb->rand_offsets)); if (pmb->rand_offsets == NULL) { perror("malloc"); ret = -1; goto err_free_pmb; } for (size_t i = 0; i < pmb->n_rand_offsets; ++i) pmb->rand_offsets[i] = rand() % args->n_ops_per_thread; /* create a pmem file and memory map it */ if ((pmb->pmem_addr = (unsigned char *)pmem_map_file( args->fname, pmb->fsize, PMEM_FILE_CREATE | PMEM_FILE_EXCL, args->fmode, NULL, NULL)) == NULL) { perror(args->fname); ret = -1; goto err_free_buf; } if (op_type == OP_TYPE_READ) { pmb->src_addr = pmb->pmem_addr; pmb->dest_addr = pmb->buf; } else { pmb->src_addr = pmb->buf; pmb->dest_addr = pmb->pmem_addr; } /* set proper func_src() and func_dest() depending on benchmark args */ if ((pmb->func_src = assign_mode_func(pmb->pargs->src_mode)) == NULL) { fprintf(stderr, "wrong src_mode parameter -- '%s'", pmb->pargs->src_mode); ret = -1; goto err_unmap; } if ((pmb->func_dest = assign_mode_func(pmb->pargs->dest_mode)) == NULL) { fprintf(stderr, "wrong dest_mode parameter -- '%s'", pmb->pargs->dest_mode); ret = -1; goto err_unmap; } if (pmb->pargs->memcpy) { pmb->func_op = pmb->pargs->persist ? libc_memcpy_persist : libc_memcpy; } else { pmb->func_op = pmb->pargs->persist ? libpmem_memcpy_persist : libpmem_memcpy_nodrain; } pmembench_set_priv(bench, pmb); return 0; err_unmap: pmem_unmap(pmb->pmem_addr, pmb->fsize); err_free_buf: util_aligned_free(pmb->buf); err_free_pmb: free(pmb); return ret; } /* * pmem_memcpy_operation -- actual benchmark operation * * Depending on the memcpy flag "-m" tested operation will be memcpy() * or pmem_memcpy_persist(). */ static int pmem_memcpy_operation(struct benchmark *bench, struct operation_info *info) { struct pmem_bench *pmb = (struct pmem_bench *)pmembench_get_priv(bench); size_t src_index = info->args->n_ops_per_thread * info->worker->index + pmb->func_src(pmb, info->index); size_t dest_index = info->args->n_ops_per_thread * info->worker->index + pmb->func_dest(pmb, info->index); void *source = pmb->src_addr + src_index * pmb->pargs->chunk_size + pmb->pargs->src_off; void *dest = pmb->dest_addr + dest_index * pmb->pargs->chunk_size + pmb->pargs->dest_off; size_t len = pmb->pargs->chunk_size; pmb->func_op(dest, source, len); return 0; } /* * pmem_memcpy_exit -- benchmark cleanup */ static int pmem_memcpy_exit(struct benchmark *bench, struct benchmark_args *args) { struct pmem_bench *pmb = (struct pmem_bench *)pmembench_get_priv(bench); munmap(pmb->pmem_addr, pmb->fsize); util_aligned_free(pmb->buf); free(pmb->rand_offsets); free(pmb); return 0; } /* structure to define command line arguments */ static struct benchmark_clo pmem_memcpy_clo[7]; /* Stores information about benchmark. */ static struct benchmark_info pmem_memcpy; CONSTRUCTOR(pmem_memcpy_costructor) void pmem_memcpy_costructor(void) { pmem_memcpy_clo[0].opt_short = 'o'; pmem_memcpy_clo[0].opt_long = "operation"; pmem_memcpy_clo[0].descr = "Operation type - write, read"; pmem_memcpy_clo[0].type = CLO_TYPE_STR; pmem_memcpy_clo[0].off = clo_field_offset(struct pmem_args, operation); pmem_memcpy_clo[0].def = "write"; pmem_memcpy_clo[1].opt_short = 'S'; pmem_memcpy_clo[1].opt_long = "src-offset"; pmem_memcpy_clo[1].descr = "Source cache line alignment" " offset"; pmem_memcpy_clo[1].type = CLO_TYPE_UINT; pmem_memcpy_clo[1].off = clo_field_offset(struct pmem_args, src_off); pmem_memcpy_clo[1].def = "0"; pmem_memcpy_clo[1].type_uint.size = clo_field_size(struct pmem_args, src_off); pmem_memcpy_clo[1].type_uint.base = CLO_INT_BASE_DEC; pmem_memcpy_clo[1].type_uint.min = 0; pmem_memcpy_clo[1].type_uint.max = MAX_OFFSET; pmem_memcpy_clo[2].opt_short = 'D'; pmem_memcpy_clo[2].opt_long = "dest-offset"; pmem_memcpy_clo[2].descr = "Destination cache line " "alignment offset"; pmem_memcpy_clo[2].type = CLO_TYPE_UINT; pmem_memcpy_clo[2].off = clo_field_offset(struct pmem_args, dest_off); pmem_memcpy_clo[2].def = "0"; pmem_memcpy_clo[2].type_uint.size = clo_field_size(struct pmem_args, dest_off); pmem_memcpy_clo[2].type_uint.base = CLO_INT_BASE_DEC; pmem_memcpy_clo[2].type_uint.min = 0; pmem_memcpy_clo[2].type_uint.max = MAX_OFFSET; pmem_memcpy_clo[3].opt_short = 0; pmem_memcpy_clo[3].opt_long = "src-mode"; pmem_memcpy_clo[3].descr = "Source reading mode"; pmem_memcpy_clo[3].type = CLO_TYPE_STR; pmem_memcpy_clo[3].off = clo_field_offset(struct pmem_args, src_mode); pmem_memcpy_clo[3].def = "seq"; pmem_memcpy_clo[4].opt_short = 0; pmem_memcpy_clo[4].opt_long = "dest-mode"; pmem_memcpy_clo[4].descr = "Destination writing mode"; pmem_memcpy_clo[4].type = CLO_TYPE_STR; pmem_memcpy_clo[4].off = clo_field_offset(struct pmem_args, dest_mode); pmem_memcpy_clo[4].def = "seq"; pmem_memcpy_clo[5].opt_short = 'm'; pmem_memcpy_clo[5].opt_long = "libc-memcpy"; pmem_memcpy_clo[5].descr = "Use libc memcpy()"; pmem_memcpy_clo[5].type = CLO_TYPE_FLAG; pmem_memcpy_clo[5].off = clo_field_offset(struct pmem_args, memcpy); pmem_memcpy_clo[5].def = "false"; pmem_memcpy_clo[6].opt_short = 'p'; pmem_memcpy_clo[6].opt_long = "persist"; pmem_memcpy_clo[6].descr = "Use pmem_persist()"; pmem_memcpy_clo[6].type = CLO_TYPE_FLAG; pmem_memcpy_clo[6].off = clo_field_offset(struct pmem_args, persist); pmem_memcpy_clo[6].def = "true"; pmem_memcpy.name = "pmem_memcpy"; pmem_memcpy.brief = "Benchmark for" "pmem_memcpy_persist() and " "pmem_memcpy_nodrain()" "operations"; pmem_memcpy.init = pmem_memcpy_init; pmem_memcpy.exit = pmem_memcpy_exit; pmem_memcpy.multithread = true; pmem_memcpy.multiops = true; pmem_memcpy.operation = pmem_memcpy_operation; pmem_memcpy.measure_time = true; pmem_memcpy.clos = pmem_memcpy_clo; pmem_memcpy.nclos = ARRAY_SIZE(pmem_memcpy_clo); pmem_memcpy.opts_size = sizeof(struct pmem_args); pmem_memcpy.rm_file = true; pmem_memcpy.allow_poolset = false; REGISTER_BENCHMARK(pmem_memcpy); }; pmdk-1.4.1/src/benchmarks/pmem_memset.cpp000066400000000000000000000277131331545616200204100ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmem_memset.cpp -- benchmark for pmem_memset function */ #include #include #include #include #include #include #include #include #include "benchmark.hpp" #include "os.h" #define MAX_OFFSET 63 #define CONST_B 0xFF struct memset_bench; typedef int (*operation_fn)(void *dest, int c, size_t len); /* * memset_args -- benchmark specific command line options */ struct memset_args { char *mode; /* operation mode: stat, seq, rand */ bool memset; /* use libc memset function */ bool persist; /* perform persist operation */ bool msync; /* perform msync operation */ bool no_warmup; /* do not do warmup */ size_t chunk_size; /* elementary chunk size */ size_t dest_off; /* destination address offset */ unsigned seed; /* seed for random numbers */ }; /* * memset_bench -- benchmark context */ struct memset_bench { struct memset_args *pargs; /* benchmark specific arguments */ uint64_t *offsets; /* random/sequential address offsets */ size_t n_offsets; /* number of random elements */ int const_b; /* memset() value */ size_t fsize; /* file size */ void *pmem_addr; /* mapped file address */ operation_fn func_op; /* operation function */ }; /* * operation_mode -- mode of operation of memset() */ enum operation_mode { OP_MODE_UNKNOWN, OP_MODE_STAT, /* always use the same chunk */ OP_MODE_SEQ, /* use consecutive chunks */ OP_MODE_RAND /* use random chunks */ }; /* * parse_op_mode -- parse operation mode from string */ static enum operation_mode parse_op_mode(const char *arg) { if (strcmp(arg, "stat") == 0) return OP_MODE_STAT; else if (strcmp(arg, "seq") == 0) return OP_MODE_SEQ; else if (strcmp(arg, "rand") == 0) return OP_MODE_RAND; else return OP_MODE_UNKNOWN; } /* * init_offsets -- initialize offsets[] array depending on the selected mode */ static int init_offsets(struct benchmark_args *args, struct memset_bench *mb, enum operation_mode op_mode) { unsigned n_threads = args->n_threads; size_t n_ops = args->n_ops_per_thread; mb->n_offsets = n_ops * n_threads; assert(mb->n_offsets != 0); mb->offsets = (uint64_t *)malloc(mb->n_offsets * sizeof(*mb->offsets)); if (!mb->offsets) { perror("malloc"); return -1; } unsigned seed = mb->pargs->seed; for (unsigned i = 0; i < n_threads; i++) { for (size_t j = 0; j < n_ops; j++) { size_t o; switch (op_mode) { case OP_MODE_STAT: o = i; break; case OP_MODE_SEQ: o = i * n_ops + j; break; case OP_MODE_RAND: o = i * n_ops + os_rand_r(&seed) % n_ops; break; default: assert(0); return -1; } mb->offsets[i * n_ops + j] = o * mb->pargs->chunk_size; } } return 0; } /* * libpmem_memset_persist -- perform operation using libpmem * pmem_memset_persist(). */ static int libpmem_memset_persist(void *dest, int c, size_t len) { pmem_memset_persist(dest, c, len); return 0; } /* * libpmem_memset_nodrain -- perform operation using libpmem * pmem_memset_nodrain(). */ static int libpmem_memset_nodrain(void *dest, int c, size_t len) { pmem_memset_nodrain(dest, c, len); return 0; } /* * libc_memset_persist -- perform operation using libc memset() function * followed by pmem_persist(). */ static int libc_memset_persist(void *dest, int c, size_t len) { memset(dest, c, len); pmem_persist(dest, len); return 0; } /* * libc_memset_msync -- perform operation using libc memset() function * followed by pmem_msync(). */ static int libc_memset_msync(void *dest, int c, size_t len) { memset(dest, c, len); return pmem_msync(dest, len); } /* * libc_memset -- perform operation using libc memset() function * followed by pmem_flush(). */ static int libc_memset(void *dest, int c, size_t len) { memset(dest, c, len); pmem_flush(dest, len); return 0; } /* * warmup_persist -- does the warmup by writing the whole pool area */ static int warmup_persist(struct memset_bench *mb) { void *dest = mb->pmem_addr; int c = mb->const_b; size_t len = mb->fsize; pmem_memset_persist(dest, c, len); return 0; } /* * warmup_msync -- does the warmup by writing the whole pool area */ static int warmup_msync(struct memset_bench *mb) { void *dest = mb->pmem_addr; int c = mb->const_b; size_t len = mb->fsize; return libc_memset_msync(dest, c, len); } /* * memset_op -- actual benchmark operation. It can have one of the four * functions assigned: * libc_memset, * libc_memset_persist, * libpmem_memset_nodrain, * libpmem_memset_persist. */ static int memset_op(struct benchmark *bench, struct operation_info *info) { struct memset_bench *mb = (struct memset_bench *)pmembench_get_priv(bench); assert(info->index < mb->n_offsets); size_t idx = info->worker->index * info->args->n_ops_per_thread + info->index; void *dest = (char *)mb->pmem_addr + mb->offsets[idx] + mb->pargs->dest_off; int c = mb->const_b; size_t len = mb->pargs->chunk_size; mb->func_op(dest, c, len); return 0; } /* * memset_init -- initialization function */ static int memset_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); int ret = 0; size_t size; size_t large; size_t little; int (*warmup_func)(struct memset_bench *) = warmup_persist; struct memset_bench *mb = (struct memset_bench *)malloc(sizeof(struct memset_bench)); if (!mb) { perror("malloc"); return -1; } mb->pargs = (struct memset_args *)args->opts; mb->pargs->chunk_size = args->dsize; enum operation_mode op_mode = parse_op_mode(mb->pargs->mode); if (op_mode == OP_MODE_UNKNOWN) { fprintf(stderr, "Invalid operation mode argument '%s'\n", mb->pargs->mode); ret = -1; goto err_free_mb; } size = MAX_OFFSET + mb->pargs->chunk_size; large = size * args->n_ops_per_thread * args->n_threads; little = size * args->n_threads; mb->fsize = (op_mode == OP_MODE_STAT) ? little : large; /* initialize offsets[] array depending on benchmark args */ if (init_offsets(args, mb, op_mode) < 0) { ret = -1; goto err_free_mb; } /* initialize memset() value */ mb->const_b = CONST_B; /* create a pmem file and memory map it */ if ((mb->pmem_addr = pmem_map_file(args->fname, mb->fsize, PMEM_FILE_CREATE | PMEM_FILE_EXCL, args->fmode, NULL, NULL)) == NULL) { perror(args->fname); ret = -1; goto err_free_offsets; } if (mb->pargs->memset) { if (mb->pargs->persist && mb->pargs->msync) { fprintf(stderr, "Invalid benchmark parameters: " "persist and msync cannot be specified " "together\n"); ret = -1; goto err_free_offsets; } if (mb->pargs->persist) { mb->func_op = libc_memset_persist; } else if (mb->pargs->msync) { mb->func_op = libc_memset_msync; warmup_func = warmup_msync; } else { mb->func_op = libc_memset; } } else { mb->func_op = (mb->pargs->persist) ? libpmem_memset_persist : libpmem_memset_nodrain; } if (!mb->pargs->no_warmup) { ret = warmup_func(mb); if (ret) { perror("Pool warmup failed"); goto err_free_offsets; } } pmembench_set_priv(bench, mb); return ret; err_free_offsets: free(mb->offsets); err_free_mb: free(mb); return ret; } /* * memset_exit -- benchmark cleanup function */ static int memset_exit(struct benchmark *bench, struct benchmark_args *args) { struct memset_bench *mb = (struct memset_bench *)pmembench_get_priv(bench); pmem_unmap(mb->pmem_addr, mb->fsize); free(mb->offsets); free(mb); return 0; } static struct benchmark_clo memset_clo[7]; /* Stores information about benchmark. */ static struct benchmark_info memset_info; CONSTRUCTOR(pmem_memset_costructor) void pmem_memset_costructor(void) { memset_clo[0].opt_short = 'M'; memset_clo[0].opt_long = "mem-mode"; memset_clo[0].descr = "Memory writing mode - " "stat, seq, rand"; memset_clo[0].def = "seq"; memset_clo[0].off = clo_field_offset(struct memset_args, mode); memset_clo[0].type = CLO_TYPE_STR; memset_clo[1].opt_short = 'm'; memset_clo[1].opt_long = "memset"; memset_clo[1].descr = "Use libc memset()"; memset_clo[1].def = "false"; memset_clo[1].off = clo_field_offset(struct memset_args, memset); memset_clo[1].type = CLO_TYPE_FLAG; memset_clo[2].opt_short = 'p'; memset_clo[2].opt_long = "persist"; memset_clo[2].descr = "Use pmem_persist()"; memset_clo[2].def = "true"; memset_clo[2].off = clo_field_offset(struct memset_args, persist); memset_clo[2].type = CLO_TYPE_FLAG; memset_clo[3].opt_short = 'D'; memset_clo[3].opt_long = "dest-offset"; memset_clo[3].descr = "Destination cache line alignment " "offset"; memset_clo[3].def = "0"; memset_clo[3].off = clo_field_offset(struct memset_args, dest_off); memset_clo[3].type = CLO_TYPE_UINT; memset_clo[3].type_uint.size = clo_field_size(struct memset_args, dest_off); memset_clo[3].type_uint.base = CLO_INT_BASE_DEC; memset_clo[3].type_uint.min = 0; memset_clo[3].type_uint.max = MAX_OFFSET; memset_clo[4].opt_short = 'w'; memset_clo[4].opt_long = "no-warmup"; memset_clo[4].descr = "Don't do warmup"; memset_clo[4].def = "false"; memset_clo[4].type = CLO_TYPE_FLAG; memset_clo[4].off = clo_field_offset(struct memset_args, no_warmup); memset_clo[5].opt_short = 'S'; memset_clo[5].opt_long = "seed"; memset_clo[5].descr = "seed for random numbers"; memset_clo[5].def = "1"; memset_clo[5].off = clo_field_offset(struct memset_args, seed); memset_clo[5].type = CLO_TYPE_UINT; memset_clo[5].type_uint.size = clo_field_size(struct memset_args, seed); memset_clo[5].type_uint.base = CLO_INT_BASE_DEC; memset_clo[5].type_uint.min = 1; memset_clo[5].type_uint.max = UINT_MAX; memset_clo[6].opt_short = 's'; memset_clo[6].opt_long = "msync"; memset_clo[6].descr = "Use pmem_msync()"; memset_clo[6].def = "false"; memset_clo[6].off = clo_field_offset(struct memset_args, msync); memset_clo[6].type = CLO_TYPE_FLAG; memset_info.name = "pmem_memset"; memset_info.brief = "Benchmark for pmem_memset_persist() " "and pmem_memset_nodrain() operations"; memset_info.init = memset_init; memset_info.exit = memset_exit; memset_info.multithread = true; memset_info.multiops = true; memset_info.operation = memset_op; memset_info.measure_time = true; memset_info.clos = memset_clo; memset_info.nclos = ARRAY_SIZE(memset_clo); memset_info.opts_size = sizeof(struct memset_args); memset_info.rm_file = true; memset_info.allow_poolset = false; REGISTER_BENCHMARK(memset_info); }; pmdk-1.4.1/src/benchmarks/pmembench.cpp000066400000000000000000001214201331545616200200240ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmembench.cpp -- main source file for benchmark framework */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "benchmark.hpp" #include "benchmark_worker.hpp" #include "clo.hpp" #include "clo_vec.hpp" #include "config_reader.hpp" #include "file.h" #include "mmap.h" #include "os.h" #include "os_thread.h" #include "queue.h" #include "scenario.hpp" #include "set.h" #include "util.h" #ifndef _WIN32 #include "rpmem_common.h" #include "rpmem_ssh.h" #include "rpmem_util.h" #endif /* average time required to get a current time from the system */ unsigned long long Get_time_avg; #define MIN_EXE_TIME_E 0.5 /* * struct pmembench -- main context */ struct pmembench { int argc; char **argv; struct scenario *scenario; struct clo_vec *clovec; bool override_clos; }; /* * struct benchmark -- benchmark's context */ struct benchmark { LIST_ENTRY(benchmark) next; struct benchmark_info *info; void *priv; struct benchmark_clo *clos; size_t nclos; size_t args_size; }; /* * struct results -- statistics for total measurements */ struct results { double min; double max; double avg; double std_dev; double med; }; /* * struct latency -- statistics for latency measurements */ struct latency { uint64_t max; uint64_t min; uint64_t avg; double std_dev; uint64_t pctl99_0p; uint64_t pctl99_9p; }; /* * struct thread_results -- results of a single thread */ struct thread_results { benchmark_time_t beg; benchmark_time_t end; benchmark_time_t end_op[]; }; /* * struct bench_results -- results of the whole benchmark */ struct bench_results { struct thread_results **thres; }; /* * struct total_results -- results and statistics of the whole benchmark */ struct total_results { size_t nrepeats; size_t nthreads; size_t nops; double nopsps; struct results total; struct latency latency; struct bench_results *res; }; /* * struct bench_list -- list of available benchmarks */ struct bench_list { LIST_HEAD(benchmarks_head, benchmark) head; bool initialized; }; /* * struct benchmark_opts -- arguments for pmembench */ struct benchmark_opts { bool help; bool version; const char *file_name; }; static struct version_s { unsigned major; unsigned minor; } version = {1, 0}; /* benchmarks list initialization */ static struct bench_list benchmarks; /* common arguments for benchmarks */ static struct benchmark_clo pmembench_clos[12]; /* list of arguments for pmembench */ static struct benchmark_clo pmembench_opts[2]; CONSTRUCTOR(pmembench_costructor) void pmembench_costructor(void) { pmembench_opts[0].opt_short = 'h'; pmembench_opts[0].opt_long = "help"; pmembench_opts[0].descr = "Print help"; pmembench_opts[0].type = CLO_TYPE_FLAG; pmembench_opts[0].off = clo_field_offset(struct benchmark_opts, help); pmembench_opts[0].ignore_in_res = true; pmembench_opts[1].opt_short = 'v'; pmembench_opts[1].opt_long = "version"; pmembench_opts[1].descr = "Print version"; pmembench_opts[1].type = CLO_TYPE_FLAG; pmembench_opts[1].off = clo_field_offset(struct benchmark_opts, version); pmembench_opts[1].ignore_in_res = true; pmembench_clos[0].opt_short = 'h'; pmembench_clos[0].opt_long = "help"; pmembench_clos[0].descr = "Print help for single benchmark"; pmembench_clos[0].type = CLO_TYPE_FLAG; pmembench_clos[0].off = clo_field_offset(struct benchmark_args, help); pmembench_clos[0].ignore_in_res = true; pmembench_clos[1].opt_short = 't'; pmembench_clos[1].opt_long = "threads"; pmembench_clos[1].type = CLO_TYPE_UINT; pmembench_clos[1].descr = "Number of working threads"; pmembench_clos[1].off = clo_field_offset(struct benchmark_args, n_threads); pmembench_clos[1].def = "1"; pmembench_clos[1].type_uint.size = clo_field_size(struct benchmark_args, n_threads); pmembench_clos[1].type_uint.base = CLO_INT_BASE_DEC; pmembench_clos[1].type_uint.min = 1; pmembench_clos[1].type_uint.max = UINT_MAX; pmembench_clos[2].opt_short = 'n'; pmembench_clos[2].opt_long = "ops-per-thread"; pmembench_clos[2].type = CLO_TYPE_UINT; pmembench_clos[2].descr = "Number of operations per thread"; pmembench_clos[2].off = clo_field_offset(struct benchmark_args, n_ops_per_thread); pmembench_clos[2].def = "1"; pmembench_clos[2].type_uint.size = clo_field_size(struct benchmark_args, n_ops_per_thread); pmembench_clos[2].type_uint.base = CLO_INT_BASE_DEC; pmembench_clos[2].type_uint.min = 1; pmembench_clos[2].type_uint.max = ULLONG_MAX; pmembench_clos[3].opt_short = 'd'; pmembench_clos[3].opt_long = "data-size"; pmembench_clos[3].type = CLO_TYPE_UINT; pmembench_clos[3].descr = "IO data size"; pmembench_clos[3].off = clo_field_offset(struct benchmark_args, dsize); pmembench_clos[3].def = "1"; pmembench_clos[3].type_uint.size = clo_field_size(struct benchmark_args, dsize); pmembench_clos[3].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; pmembench_clos[3].type_uint.min = 1; pmembench_clos[3].type_uint.max = ULONG_MAX; pmembench_clos[4].opt_short = 'f'; pmembench_clos[4].opt_long = "file"; pmembench_clos[4].type = CLO_TYPE_STR; pmembench_clos[4].descr = "File name"; pmembench_clos[4].off = clo_field_offset(struct benchmark_args, fname); pmembench_clos[4].def = "/mnt/pmem/testfile"; pmembench_clos[4].ignore_in_res = true; pmembench_clos[5].opt_short = 'm'; pmembench_clos[5].opt_long = "fmode"; pmembench_clos[5].type = CLO_TYPE_UINT; pmembench_clos[5].descr = "File mode"; pmembench_clos[5].off = clo_field_offset(struct benchmark_args, fmode); pmembench_clos[5].def = "0666"; pmembench_clos[5].ignore_in_res = true; pmembench_clos[5].type_uint.size = clo_field_size(struct benchmark_args, fmode); pmembench_clos[5].type_uint.base = CLO_INT_BASE_OCT; pmembench_clos[5].type_uint.min = 0; pmembench_clos[5].type_uint.max = ULONG_MAX; pmembench_clos[6].opt_short = 's'; pmembench_clos[6].opt_long = "seed"; pmembench_clos[6].type = CLO_TYPE_UINT; pmembench_clos[6].descr = "PRNG seed"; pmembench_clos[6].off = clo_field_offset(struct benchmark_args, seed); pmembench_clos[6].def = "0"; pmembench_clos[6].type_uint.size = clo_field_size(struct benchmark_args, seed); pmembench_clos[6].type_uint.base = CLO_INT_BASE_DEC; pmembench_clos[6].type_uint.min = 0; pmembench_clos[6].type_uint.max = ~0; pmembench_clos[7].opt_short = 'r'; pmembench_clos[7].opt_long = "repeats"; pmembench_clos[7].type = CLO_TYPE_UINT; pmembench_clos[7].descr = "Number of repeats of scenario"; pmembench_clos[7].off = clo_field_offset(struct benchmark_args, repeats); pmembench_clos[7].def = "1"; pmembench_clos[7].type_uint.size = clo_field_size(struct benchmark_args, repeats); pmembench_clos[7].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; pmembench_clos[7].type_uint.min = 1; pmembench_clos[7].type_uint.max = ULONG_MAX; pmembench_clos[8].opt_short = 'F'; pmembench_clos[8].opt_long = "thread-affinity"; pmembench_clos[8].descr = "Set worker threads CPU affinity mask"; pmembench_clos[8].type = CLO_TYPE_FLAG; pmembench_clos[8].off = clo_field_offset(struct benchmark_args, thread_affinity); pmembench_clos[8].def = "false"; /* * XXX: add link to blog post about optimal affinity * when it will be done */ pmembench_clos[9].opt_short = 'I'; pmembench_clos[9].opt_long = "affinity-list"; pmembench_clos[9].descr = "Set affinity mask as a list of CPUs separated by semicolon"; pmembench_clos[9].type = CLO_TYPE_STR; pmembench_clos[9].off = clo_field_offset(struct benchmark_args, affinity_list); pmembench_clos[9].def = ""; pmembench_clos[9].ignore_in_res = true; pmembench_clos[10].opt_long = "main-affinity"; pmembench_clos[10].descr = "Set affinity for main thread"; pmembench_clos[10].type = CLO_TYPE_INT; pmembench_clos[10].off = clo_field_offset(struct benchmark_args, main_affinity); pmembench_clos[10].def = "-1"; pmembench_clos[10].ignore_in_res = false; pmembench_clos[10].type_int.size = clo_field_size(struct benchmark_args, main_affinity); pmembench_clos[10].type_int.base = CLO_INT_BASE_DEC; pmembench_clos[10].type_int.min = (-1); pmembench_clos[10].type_int.max = LONG_MAX; pmembench_clos[11].opt_short = 'e'; pmembench_clos[11].opt_long = "min-exe-time"; pmembench_clos[11].type = CLO_TYPE_UINT; pmembench_clos[11].descr = "Minimal execution time in seconds"; pmembench_clos[11].off = clo_field_offset(struct benchmark_args, min_exe_time); pmembench_clos[11].def = "0"; pmembench_clos[11].type_uint.size = clo_field_size(struct benchmark_args, min_exe_time); pmembench_clos[11].type_uint.base = CLO_INT_BASE_DEC; pmembench_clos[11].type_uint.min = 0; pmembench_clos[11].type_uint.max = ULONG_MAX; } /* * pmembench_get_priv -- return private structure of benchmark */ void * pmembench_get_priv(struct benchmark *bench) { return bench->priv; } /* * pmembench_set_priv -- set private structure of benchmark */ void pmembench_set_priv(struct benchmark *bench, void *priv) { bench->priv = priv; } /* * pmembench_register -- register benchmark */ int pmembench_register(struct benchmark_info *bench_info) { struct benchmark *bench = (struct benchmark *)calloc(1, sizeof(*bench)); assert(bench != NULL); bench->info = bench_info; if (!benchmarks.initialized) { LIST_INIT(&benchmarks.head); benchmarks.initialized = true; } LIST_INSERT_HEAD(&benchmarks.head, bench, next); return 0; } /* * pmembench_get_info -- return structure with information about benchmark */ struct benchmark_info * pmembench_get_info(struct benchmark *bench) { return bench->info; } /* * pmembench_release_clos -- release CLO structure */ static void pmembench_release_clos(struct benchmark *bench) { free(bench->clos); } /* * pmembench_merge_clos -- merge benchmark's CLOs with common CLOs */ static void pmembench_merge_clos(struct benchmark *bench) { size_t size = sizeof(struct benchmark_args); size_t pb_nclos = ARRAY_SIZE(pmembench_clos); size_t nclos = pb_nclos; size_t i; if (bench->info->clos) { size += bench->info->opts_size; nclos += bench->info->nclos; } struct benchmark_clo *clos = (struct benchmark_clo *)calloc( nclos, sizeof(struct benchmark_clo)); assert(clos != NULL); memcpy(clos, pmembench_clos, pb_nclos * sizeof(struct benchmark_clo)); if (bench->info->clos) { memcpy(&clos[pb_nclos], bench->info->clos, bench->info->nclos * sizeof(struct benchmark_clo)); for (i = 0; i < bench->info->nclos; i++) { clos[pb_nclos + i].off += sizeof(struct benchmark_args); } } bench->clos = clos; bench->nclos = nclos; bench->args_size = size; } /* * pmembench_run_worker -- run worker with benchmark operation */ static int pmembench_run_worker(struct benchmark *bench, struct worker_info *winfo) { benchmark_time_get(&winfo->beg); for (size_t i = 0; i < winfo->nops; i++) { if (bench->info->operation(bench, &winfo->opinfo[i])) return -1; benchmark_time_get(&winfo->opinfo[i].end); } benchmark_time_get(&winfo->end); return 0; } /* * pmembench_print_header -- print header of benchmark's results */ static void pmembench_print_header(struct pmembench *pb, struct benchmark *bench, struct clo_vec *clovec) { if (pb->scenario) { printf("%s: %s [%" PRIu64 "]%s%s%s\n", pb->scenario->name, bench->info->name, clovec->nargs, pb->scenario->group ? " [group: " : "", pb->scenario->group ? pb->scenario->group : "", pb->scenario->group ? "]" : ""); } else { printf("%s [%" PRIu64 "]\n", bench->info->name, clovec->nargs); } printf("total-avg[sec];" "ops-per-second[1/sec];" "total-max[sec];" "total-min[sec];" "total-median[sec];" "total-std-dev[sec];" "latency-avg[nsec];" "latency-min[nsec];" "latency-max[nsec];" "latency-std-dev[nsec];" "latency-pctl-99.0%%[nsec];" "latency-pctl-99.9%%[nsec]"); size_t i; for (i = 0; i < bench->nclos; i++) { if (!bench->clos[i].ignore_in_res) { printf(";%s", bench->clos[i].opt_long); } } printf("\n"); } /* * pmembench_print_results -- print benchmark's results */ static void pmembench_print_results(struct benchmark *bench, struct benchmark_args *args, struct total_results *res) { printf("%f;%f;%f;%f;%f;%f;%" PRIu64 ";%" PRIu64 ";%" PRIu64 ";%f;%" PRIu64 ";%" PRIu64, res->total.avg, res->nopsps, res->total.max, res->total.min, res->total.med, res->total.std_dev, res->latency.avg, res->latency.min, res->latency.max, res->latency.std_dev, res->latency.pctl99_0p, res->latency.pctl99_9p); size_t i; for (i = 0; i < bench->nclos; i++) { if (!bench->clos[i].ignore_in_res) printf(";%s", benchmark_clo_str(&bench->clos[i], args, bench->args_size)); } printf("\n"); } /* * pmembench_parse_clos -- parse command line arguments for benchmark */ static int pmembench_parse_clo(struct pmembench *pb, struct benchmark *bench, struct clo_vec *clovec) { if (!pb->scenario) { return benchmark_clo_parse(pb->argc, pb->argv, bench->clos, bench->nclos, clovec); } if (pb->override_clos) { /* * Use only ARRAY_SIZE(pmembench_clos) clos - these are the * general clos and are placed at the beginning of the * clos array. */ int ret = benchmark_override_clos_in_scenario( pb->scenario, pb->argc, pb->argv, bench->clos, ARRAY_SIZE(pmembench_clos)); /* reset for the next benchmark in the config file */ optind = 1; if (ret) return ret; } return benchmark_clo_parse_scenario(pb->scenario, bench->clos, bench->nclos, clovec); } /* * pmembench_parse_affinity -- parse affinity list */ static int pmembench_parse_affinity(const char *list, char **saveptr) { char *str = NULL; char *end; int cpu = 0; if (*saveptr) { str = strtok(NULL, ";"); if (str == NULL) { /* end of list - we have to start over */ free(*saveptr); *saveptr = NULL; } } if (!*saveptr) { *saveptr = strdup(list); if (*saveptr == NULL) { perror("strdup"); return -1; } str = strtok(*saveptr, ";"); if (str == NULL) goto err; } if ((str == NULL) || (*str == '\0')) goto err; cpu = strtol(str, &end, 10); if (*end != '\0') goto err; return cpu; err: errno = EINVAL; perror("pmembench_parse_affinity"); free(*saveptr); *saveptr = NULL; return -1; } /* * pmembench_init_workers -- init benchmark's workers */ static int pmembench_init_workers(struct benchmark_worker **workers, size_t nworkers, size_t n_ops, struct benchmark *bench, struct benchmark_args *args) { size_t i; int ncpus = 0; char *saveptr = NULL; int ret = 0; if (args->thread_affinity) { ncpus = sysconf(_SC_NPROCESSORS_ONLN); if (ncpus <= 0) return -1; } for (i = 0; i < nworkers; i++) { workers[i] = benchmark_worker_alloc(); if (args->thread_affinity) { int cpu; os_cpu_set_t cpuset; if (*args->affinity_list != '\0') { cpu = pmembench_parse_affinity( args->affinity_list, &saveptr); if (cpu == -1) { ret = -1; goto end; } } else { cpu = (int)i; } assert(ncpus > 0); cpu %= ncpus; os_cpu_zero(&cpuset); os_cpu_set(cpu, &cpuset); errno = os_thread_setaffinity_np(&workers[i]->thread, sizeof(os_cpu_set_t), &cpuset); if (errno) { perror("os_thread_setaffinity_np"); ret = -1; goto end; } } workers[i]->info.index = i; workers[i]->info.nops = n_ops; workers[i]->info.opinfo = (struct operation_info *)calloc( n_ops, sizeof(struct operation_info)); size_t j; for (j = 0; j < n_ops; j++) { workers[i]->info.opinfo[j].worker = &workers[i]->info; workers[i]->info.opinfo[j].args = args; workers[i]->info.opinfo[j].index = j; } workers[i]->bench = bench; workers[i]->args = args; workers[i]->func = pmembench_run_worker; workers[i]->init = bench->info->init_worker; workers[i]->exit = bench->info->free_worker; benchmark_worker_init(workers[i]); } end: free(saveptr); return ret; } /* * results_store -- store results of a single repeat */ static void results_store(struct bench_results *res, struct benchmark_worker **workers, unsigned nthreads, size_t nops) { for (unsigned i = 0; i < nthreads; i++) { res->thres[i]->beg = workers[i]->info.beg; res->thres[i]->end = workers[i]->info.end; for (size_t j = 0; j < nops; j++) { res->thres[i]->end_op[j] = workers[i]->info.opinfo[j].end; } } } /* * compare_time -- compare time values */ static int compare_time(const void *p1, const void *p2) { const benchmark_time_t *t1 = (const benchmark_time_t *)p1; const benchmark_time_t *t2 = (const benchmark_time_t *)p2; return benchmark_time_compare(t1, t2); } /* * compare_doubles -- comparing function used for sorting */ static int compare_doubles(const void *a1, const void *b1) { const double *a = (const double *)a1; const double *b = (const double *)b1; return (*a > *b) - (*a < *b); } /* * compare_uint64t -- comparing function used for sorting */ static int compare_uint64t(const void *a1, const void *b1) { const uint64_t *a = (const uint64_t *)a1; const uint64_t *b = (const uint64_t *)b1; return (*a > *b) - (*a < *b); } /* * results_alloc -- prepare structure to store all benchmark results */ static struct total_results * results_alloc(size_t nrepeats, size_t nthreads, size_t nops) { struct total_results *total = (struct total_results *)malloc(sizeof(*total)); assert(total != NULL); total->nrepeats = nrepeats; total->nthreads = nthreads; total->nops = nops; total->res = (struct bench_results *)malloc(nrepeats * sizeof(*total->res)); assert(total->res != NULL); for (size_t i = 0; i < nrepeats; i++) { struct bench_results *res = &total->res[i]; assert(nthreads != 0); res->thres = (struct thread_results **)malloc( nthreads * sizeof(*res->thres)); assert(res->thres != NULL); for (size_t j = 0; j < nthreads; j++) { res->thres[j] = (struct thread_results *)malloc( sizeof(*res->thres[j]) + nops * sizeof(benchmark_time_t)); assert(res->thres[j] != NULL); } } return total; } /* * results_free -- release results structure */ static void results_free(struct total_results *total) { for (size_t i = 0; i < total->nrepeats; i++) { for (size_t j = 0; j < total->nthreads; j++) free(total->res[i].thres[j]); free(total->res[i].thres); } free(total->res); free(total); } /* * get_total_results -- return results of all repeats of scenario */ static void get_total_results(struct total_results *tres) { assert(tres->nrepeats != 0); assert(tres->nthreads != 0); assert(tres->nops != 0); /* reset results */ memset(&tres->total, 0, sizeof(tres->total)); memset(&tres->latency, 0, sizeof(tres->latency)); tres->total.min = DBL_MAX; tres->total.max = DBL_MIN; tres->latency.min = UINT64_MAX; tres->latency.max = 0; /* allocate helper arrays */ benchmark_time_t *tbeg = (benchmark_time_t *)malloc(tres->nthreads * sizeof(*tbeg)); assert(tbeg != NULL); benchmark_time_t *tend = (benchmark_time_t *)malloc(tres->nthreads * sizeof(*tend)); assert(tend != NULL); double *totals = (double *)malloc(tres->nrepeats * sizeof(double)); assert(totals != NULL); /* estimate total penalty of getting time from the system */ benchmark_time_t Tget; unsigned long long nsecs = tres->nops * Get_time_avg; benchmark_time_set(&Tget, nsecs); for (size_t i = 0; i < tres->nrepeats; i++) { struct bench_results *res = &tres->res[i]; /* get start and end timestamps of each worker */ for (size_t j = 0; j < tres->nthreads; j++) { tbeg[j] = res->thres[j]->beg; tend[j] = res->thres[j]->end; } /* sort start and end timestamps */ qsort(tbeg, tres->nthreads, sizeof(benchmark_time_t), compare_time); qsort(tend, tres->nthreads, sizeof(benchmark_time_t), compare_time); /* calculating time interval between start and end time */ benchmark_time_t Tbeg = tbeg[0]; benchmark_time_t Tend = tend[tres->nthreads - 1]; benchmark_time_t Ttot_ove; benchmark_time_diff(&Ttot_ove, &Tbeg, &Tend); /* * subtract time used for getting the current time from the * system */ benchmark_time_t Ttot; benchmark_time_diff(&Ttot, &Tget, &Ttot_ove); double Stot = benchmark_time_get_secs(&Ttot); if (Stot > tres->total.max) tres->total.max = Stot; if (Stot < tres->total.min) tres->total.min = Stot; tres->total.avg += Stot; totals[i] = Stot; } /* median */ qsort(totals, tres->nrepeats, sizeof(double), compare_doubles); if (tres->nrepeats % 2) { tres->total.med = totals[tres->nrepeats / 2]; } else { double m1 = totals[tres->nrepeats / 2]; double m2 = totals[tres->nrepeats / 2 - 1]; tres->total.med = (m1 + m2) / 2.0; } /* total average time */ tres->total.avg /= (double)tres->nrepeats; /* number of operations per second */ tres->nopsps = (double)tres->nops * (double)tres->nthreads / tres->total.avg; /* std deviation of total time */ for (size_t i = 0; i < tres->nrepeats; i++) { double dev = (totals[i] - tres->total.avg); dev *= dev; tres->total.std_dev += dev; } tres->total.std_dev = sqrt(tres->total.std_dev / tres->nrepeats); /* latency */ for (size_t i = 0; i < tres->nrepeats; i++) { struct bench_results *res = &tres->res[i]; for (size_t j = 0; j < tres->nthreads; j++) { struct thread_results *thres = res->thres[j]; benchmark_time_t *beg = &thres->beg; for (size_t o = 0; o < tres->nops; o++) { benchmark_time_t lat; benchmark_time_diff(&lat, beg, &thres->end_op[o]); uint64_t nsecs = benchmark_time_get_nsecs(&lat); /* min, max latency */ if (nsecs > tres->latency.max) tres->latency.max = nsecs; if (nsecs < tres->latency.min) tres->latency.min = nsecs; tres->latency.avg += nsecs; beg = &thres->end_op[o]; } } } /* average latency */ size_t count = tres->nrepeats * tres->nthreads * tres->nops; assert(count > 0); tres->latency.avg /= count; uint64_t *ntotals = (uint64_t *)calloc(count, sizeof(uint64_t)); assert(ntotals != NULL); count = 0; /* std deviation of latency and percentiles */ for (size_t i = 0; i < tres->nrepeats; i++) { struct bench_results *res = &tres->res[i]; for (size_t j = 0; j < tres->nthreads; j++) { struct thread_results *thres = res->thres[j]; benchmark_time_t *beg = &thres->beg; for (size_t o = 0; o < tres->nops; o++) { benchmark_time_t lat; benchmark_time_diff(&lat, beg, &thres->end_op[o]); uint64_t nsecs = benchmark_time_get_nsecs(&lat); uint64_t dev = (nsecs - tres->latency.avg); dev *= dev; tres->latency.std_dev += dev; beg = &thres->end_op[o]; ntotals[count] = nsecs; ++count; } } } tres->latency.std_dev = sqrt(tres->latency.std_dev / count); /* find 99.0% and 99.9% percentiles */ qsort(ntotals, count, sizeof(uint64_t), compare_uint64t); uint64_t p99_0 = count * 99 / 100; uint64_t p99_9 = count * 999 / 1000; tres->latency.pctl99_0p = ntotals[p99_0]; tres->latency.pctl99_9p = ntotals[p99_9]; free(ntotals); free(totals); free(tend); free(tbeg); } /* * pmembench_print_args -- print arguments for one benchmark */ static void pmembench_print_args(struct benchmark_clo *clos, size_t nclos) { struct benchmark_clo clo; for (size_t i = 0; i < nclos; i++) { clo = clos[i]; if (clo.opt_short != 0) printf("\t-%c,", clo.opt_short); else printf("\t"); printf("\t--%-15s\t\t%s", clo.opt_long, clo.descr); if (clo.type != CLO_TYPE_FLAG) printf(" [default: %s]", clo.def); if (clo.type == CLO_TYPE_INT) { if (clo.type_int.min != LONG_MIN) printf(" [min: %jd]", clo.type_int.min); if (clo.type_int.max != LONG_MAX) printf(" [max: %jd]", clo.type_int.max); } else if (clo.type == CLO_TYPE_UINT) { if (clo.type_uint.min != 0) printf(" [min: %ju]", clo.type_uint.min); if (clo.type_uint.max != ULONG_MAX) printf(" [max: %ju]", clo.type_uint.max); } printf("\n"); } } /* * pmembench_print_help_single -- prints help for single benchmark */ static void pmembench_print_help_single(struct benchmark *bench) { struct benchmark_info *info = bench->info; printf("%s\n%s\n", info->name, info->brief); printf("\nArguments:\n"); size_t nclos = sizeof(pmembench_clos) / sizeof(struct benchmark_clo); pmembench_print_args(pmembench_clos, nclos); if (info->clos == NULL) return; pmembench_print_args(info->clos, info->nclos); } /* * pmembench_print_usage -- print usage of framework */ static void pmembench_print_usage() { printf("Usage: $ pmembench [-h|--help] [-v|--version]" "\t[[]]\n"); printf("\t\t\t\t\t\t[[]]\n"); printf("\t\t\t\t\t\t[[[]]]\n"); } /* * pmembench_print_version -- print version of framework */ static void pmembench_print_version() { printf("Benchmark framework - version %d.%d\n", version.major, version.minor); } /* * pmembench_print_examples() -- print examples of using framework */ static void pmembench_print_examples() { printf("\nExamples:\n"); printf("$ pmembench \n"); printf(" # runs benchmark of name with arguments \n"); printf("or\n"); printf("$ pmembench \n"); printf(" # runs all scenarios from config file\n"); printf("or\n"); printf("$ pmembench [] [-h|--help [-v|--version]\n"); printf(" # prints help\n"); printf("or\n"); printf("$ pmembench \n"); printf(" # runs the specified scenario from config file\n"); printf("$ pmembench " " \n"); printf(" # runs the specified scenarios from config file and overwrites" " the given common_args from the config file\n"); } /* * pmembench_print_help -- print help for framework */ static void pmembench_print_help() { pmembench_print_version(); pmembench_print_usage(); printf("\nCommon arguments:\n"); size_t nclos = sizeof(pmembench_opts) / sizeof(struct benchmark_clo); pmembench_print_args(pmembench_opts, nclos); printf("\nAvaliable benchmarks:\n"); struct benchmark *bench = NULL; LIST_FOREACH(bench, &benchmarks.head, next) printf("\t%-20s\t\t%s\n", bench->info->name, bench->info->brief); printf("\n$ pmembench --help to print detailed information" " about benchmark arguments\n"); pmembench_print_examples(); } /* * pmembench_get_bench -- searching benchmarks by name */ static struct benchmark * pmembench_get_bench(const char *name) { struct benchmark *bench; LIST_FOREACH(bench, &benchmarks.head, next) { if (strcmp(name, bench->info->name) == 0) return bench; } return NULL; } /* * pmembench_parse_opts -- parse arguments for framework */ static int pmembench_parse_opts(struct pmembench *pb) { int ret = 0; int argc = ++pb->argc; char **argv = --pb->argv; struct benchmark_opts *opts = NULL; struct clo_vec *clovec; size_t size, n_clos; size = sizeof(struct benchmark_opts); n_clos = ARRAY_SIZE(pmembench_opts); clovec = clo_vec_alloc(size); assert(clovec != NULL); if (benchmark_clo_parse(argc, argv, pmembench_opts, n_clos, clovec)) { ret = -1; goto out; } opts = (struct benchmark_opts *)clo_vec_get_args(clovec, 0); if (opts == NULL) { ret = -1; goto out; } if (opts->help) pmembench_print_help(); if (opts->version) pmembench_print_version(); out: clo_vec_free(clovec); return ret; } /* * remove_part_cb -- callback function for removing all pool set part files */ static int remove_part_cb(struct part_file *pf, void *arg) { #ifdef RPMEM_AVAILABLE if (pf->is_remote) return rpmem_remove(pf->node_addr, pf->pool_desc, RPMEM_REMOVE_FORCE); #endif const char *part_file = pf->path; if (os_access(part_file, F_OK) == 0) return util_unlink(part_file); return 0; } /* * pmembench_remove_file -- remove file or directory if exists */ static int pmembench_remove_file(const char *path) { int ret = 0; os_stat_t status; char *tmp; if (os_access(path, F_OK) != 0) return 0; if (os_stat(path, &status) != 0) return 0; if (!(status.st_mode & S_IFDIR)) { ret = util_is_poolset_file(path); if (ret == 0) { return util_unlink(path); } else if (ret == 1) { return util_poolset_foreach_part(path, remove_part_cb, NULL); } return ret; } struct dir_handle it; struct file_info info; if (util_file_dir_open(&it, path)) { return -1; } while (util_file_dir_next(&it, &info) == 0) { if (strcmp(info.filename, ".") == 0 || strcmp(info.filename, "..") == 0) continue; tmp = (char *)malloc(strlen(path) + strlen(info.filename) + 2); if (tmp == NULL) return -1; sprintf(tmp, "%s/%s", path, info.filename); ret = info.is_dir ? pmembench_remove_file(tmp) : util_unlink(tmp); free(tmp); if (ret != 0) { util_file_dir_close(&it); return ret; } } util_file_dir_close(&it); return util_file_dir_remove(path); } /* * pmembench_single_repeat -- runs benchmark ones */ static int pmembench_single_repeat(struct benchmark *bench, struct benchmark_args *args, size_t n_threads, size_t n_ops, struct bench_results *res) { int ret = 0; if (args->main_affinity != -1) { os_cpu_set_t cpuset; os_cpu_zero(&cpuset); os_thread_t self; os_thread_self(&self); os_cpu_set(args->main_affinity, &cpuset); errno = os_thread_setaffinity_np(&self, sizeof(os_cpu_set_t), &cpuset); if (errno) { perror("os_thread_setaffinity_np"); return -1; } sched_yield(); } if (bench->info->rm_file) { ret = pmembench_remove_file(args->fname); if (ret != 0) { perror("removing file failed"); return ret; } } if (bench->info->init) { if (bench->info->init(bench, args)) { warn("%s: initialization failed", bench->info->name); return -1; } } assert(bench->info->operation != NULL); assert(args->n_threads != 0); struct benchmark_worker **workers; workers = (struct benchmark_worker **)malloc( args->n_threads * sizeof(struct benchmark_worker *)); assert(workers != NULL); if ((ret = pmembench_init_workers(workers, n_threads, n_ops, bench, args)) != 0) { goto out; } unsigned j; for (j = 0; j < args->n_threads; j++) { benchmark_worker_run(workers[j]); } for (j = 0; j < args->n_threads; j++) { benchmark_worker_join(workers[j]); if (workers[j]->ret != 0) { ret = workers[j]->ret; fprintf(stderr, "thread number %d failed\n", j); } } results_store(res, workers, args->n_threads, args->n_ops_per_thread); for (j = 0; j < args->n_threads; j++) { benchmark_worker_exit(workers[j]); free(workers[j]->info.opinfo); benchmark_worker_free(workers[j]); } out: free(workers); if (bench->info->exit) bench->info->exit(bench, args); return ret; } /* * scale_up_min_exe_time -- scale up the number of operations to obtain an * execution time not smaller than the assumed minimal execution time */ int scale_up_min_exe_time(struct benchmark *bench, struct benchmark_args *args, struct total_results **total_results, size_t n_threads, size_t n_ops) { const double min_exe_time = args->min_exe_time; struct total_results *total_res = *total_results; total_res->nrepeats = 1; do { /* * run single benchmark repeat to probe execution time */ int ret = pmembench_single_repeat(bench, args, n_threads, n_ops, &total_res->res[0]); if (ret != 0) return 1; get_total_results(total_res); if (min_exe_time < total_res->total.min + MIN_EXE_TIME_E) break; /* * scale up number of operations to get assumed minimal * execution time */ n_ops = (size_t)((double)n_ops * (min_exe_time + MIN_EXE_TIME_E) / total_res->total.min); args->n_ops_per_thread = n_ops; results_free(total_res); *total_results = results_alloc(args->repeats, args->n_threads, args->n_ops_per_thread); assert(*total_results != NULL); total_res = *total_results; total_res->nrepeats = 1; } while (1); total_res->nrepeats = args->repeats; return 0; } /* * pmembench_run -- runs one benchmark. Parses arguments and performs * specific functions. */ static int pmembench_run(struct pmembench *pb, struct benchmark *bench) { char old_wd[PATH_MAX]; int ret = 0; struct benchmark_args *args = NULL; struct total_results *total_res = NULL; struct latency *stats = NULL; double *workers_times = NULL; struct clo_vec *clovec = NULL; assert(bench->info != NULL); pmembench_merge_clos(bench); /* * Check if PMEMBENCH_DIR env var is set and change * the working directory accordingly. */ char *wd = os_getenv("PMEMBENCH_DIR"); if (wd != NULL) { /* get current dir name */ if (getcwd(old_wd, PATH_MAX) == NULL) { perror("getcwd"); ret = -1; goto out_release_clos; } os_stat_t stat_buf; if (os_stat(wd, &stat_buf) != 0) { perror("os_stat"); ret = -1; goto out_release_clos; } if (!S_ISDIR(stat_buf.st_mode)) { warn("PMEMBENCH_DIR is not a directory: %s", wd); ret = -1; goto out_release_clos; } if (chdir(wd)) { perror("chdir(wd)"); ret = -1; goto out_release_clos; } } if (bench->info->pre_init) { if (bench->info->pre_init(bench)) { warn("%s: pre-init failed", bench->info->name); ret = -1; goto out_old_wd; } } clovec = clo_vec_alloc(bench->args_size); assert(clovec != NULL); if (pmembench_parse_clo(pb, bench, clovec)) { warn("%s: parsing command line arguments failed", bench->info->name); ret = -1; goto out_release_args; } args = (struct benchmark_args *)clo_vec_get_args(clovec, 0); if (args == NULL) { warn("%s: parsing command line arguments failed", bench->info->name); ret = -1; goto out_release_args; } if (args->help) { pmembench_print_help_single(bench); goto out; } pmembench_print_header(pb, bench, clovec); size_t args_i; for (args_i = 0; args_i < clovec->nargs; args_i++) { args = (struct benchmark_args *)clo_vec_get_args(clovec, args_i); if (args == NULL) { warn("%s: parsing command line arguments failed", bench->info->name); ret = -1; goto out; } args->opts = (void *)((uintptr_t)args + sizeof(struct benchmark_args)); args->is_poolset = util_is_poolset_file(args->fname) == 1; if (args->is_poolset) { if (!bench->info->allow_poolset) { fprintf(stderr, "poolset files " "not supported\n"); goto out; } args->fsize = util_poolset_size(args->fname); if (!args->fsize) { fprintf(stderr, "invalid size of poolset\n"); goto out; } } size_t n_threads = !bench->info->multithread ? 1 : args->n_threads; size_t n_ops = !bench->info->multiops ? 1 : args->n_ops_per_thread; size_t n_ops_per_thread_copy = args->n_ops_per_thread; stats = (struct latency *)calloc(args->repeats, sizeof(struct latency)); assert(stats != NULL); workers_times = (double *)calloc(n_threads * args->repeats, sizeof(double)); assert(workers_times != NULL); total_res = results_alloc(args->repeats, args->n_threads, args->n_ops_per_thread); assert(total_res != NULL); unsigned i = 0; if (args->min_exe_time != 0 && bench->info->multiops) { ret = scale_up_min_exe_time(bench, args, &total_res, n_threads, n_ops); if (ret != 0) goto out; n_ops = args->n_ops_per_thread; i = 1; } for (; i < args->repeats; i++) { ret = pmembench_single_repeat(bench, args, n_threads, n_ops, &total_res->res[i]); if (ret != 0) goto out; } get_total_results(total_res); pmembench_print_results(bench, args, total_res); args->n_ops_per_thread = n_ops_per_thread_copy; results_free(total_res); free(stats); free(workers_times); total_res = NULL; stats = NULL; workers_times = NULL; } out: if (total_res) results_free(total_res); if (stats) free(stats); if (workers_times) free(workers_times); out_release_args: clo_vec_free(clovec); out_old_wd: /* restore the original working directory */ if (wd != NULL) { /* Only if PMEMBENCH_DIR env var was defined */ if (chdir(old_wd)) { perror("chdir(old_wd)"); ret = -1; } } out_release_clos: pmembench_release_clos(bench); return ret; } /* * pmembench_free_benchmarks -- release all benchmarks */ static void __attribute__((destructor)) pmembench_free_benchmarks(void) { while (!LIST_EMPTY(&benchmarks.head)) { struct benchmark *bench = LIST_FIRST(&benchmarks.head); LIST_REMOVE(bench, next); free(bench); } } /* * pmembench_run_scenario -- run single benchmark's scenario */ static int pmembench_run_scenario(struct pmembench *pb, struct scenario *scenario) { struct benchmark *bench = pmembench_get_bench(scenario->benchmark); if (NULL == bench) { fprintf(stderr, "unknown benchmark: %s\n", scenario->benchmark); return -1; } pb->scenario = scenario; return pmembench_run(pb, bench); } /* * pmembench_run_scenarios -- run all scenarios */ static int pmembench_run_scenarios(struct pmembench *pb, struct scenarios *ss) { struct scenario *scenario; FOREACH_SCENARIO(scenario, ss) { if (pmembench_run_scenario(pb, scenario) != 0) return -1; } return 0; } /* * pmembench_run_config -- run one or all scenarios from config file */ static int pmembench_run_config(struct pmembench *pb, const char *config) { struct scenarios *ss = NULL; struct config_reader *cr = config_reader_alloc(); assert(cr != NULL); int ret = 0; if ((ret = config_reader_read(cr, config))) goto out; if ((ret = config_reader_get_scenarios(cr, &ss))) goto out; assert(ss != NULL); if (pb->argc == 1) { if ((ret = pmembench_run_scenarios(pb, ss)) != 0) goto out_scenarios; } else { /* Skip the config file name in cmd line params */ int tmp_argc = pb->argc - 1; char **tmp_argv = pb->argv + 1; if (!contains_scenarios(tmp_argc, tmp_argv, ss)) { /* no scenarios in cmd line arguments - parse params */ pb->override_clos = true; if ((ret = pmembench_run_scenarios(pb, ss)) != 0) goto out_scenarios; } else { /* scenarios in cmd line */ struct scenarios *cmd_ss = scenarios_alloc(); assert(cmd_ss != NULL); int parsed_scenarios = clo_get_scenarios( tmp_argc, tmp_argv, ss, cmd_ss); if (parsed_scenarios < 0) goto out_cmd; /* * If there are any cmd line args left, treat * them as config file params override. */ if (tmp_argc - parsed_scenarios) pb->override_clos = true; /* * Skip the scenarios in the cmd line, * pmembench_run_scenarios does not expect them and will * fail otherwise. */ pb->argc -= parsed_scenarios; pb->argv += parsed_scenarios; ret = pmembench_run_scenarios(pb, cmd_ss); out_cmd: scenarios_free(cmd_ss); } } out_scenarios: scenarios_free(ss); out: config_reader_free(cr); return ret; } int main(int argc, char *argv[]) { util_init(); util_mmap_init(); /* * Parse common command line arguments and * benchmark's specific ones. */ if (argc < 2) { pmembench_print_usage(); exit(EXIT_FAILURE); } int ret = 0; int fexists; struct benchmark *bench; struct pmembench *pb = (struct pmembench *)calloc(1, sizeof(*pb)); assert(pb != NULL); Get_time_avg = benchmark_get_avg_get_time(); pb->argc = --argc; pb->argv = ++argv; char *bench_name = pb->argv[0]; if (NULL == bench_name) { ret = -1; goto out; } fexists = os_access(bench_name, R_OK) == 0; bench = pmembench_get_bench(bench_name); if (NULL != bench) ret = pmembench_run(pb, bench); else if (fexists) ret = pmembench_run_config(pb, bench_name); else if ((ret = pmembench_parse_opts(pb)) != 0) { pmembench_print_usage(); goto out; } out: free(pb); util_mmap_fini(); return ret; } #ifdef _MSC_VER extern "C" { /* * Since libpmemobj is linked statically, * we need to invoke its ctor/dtor. */ MSVC_CONSTR(libpmemobj_init) MSVC_DESTR(libpmemobj_fini) } #endif pmdk-1.4.1/src/benchmarks/pmembench.vcxproj000066400000000000000000000345701331545616200207460ustar00rootroot00000000000000 Debug x64 Release x64 {492baa3d-0d5d-478e-9765-500463ae69aa} {49a7cc5a-d5e7-4a07-917f-c6918b982be8} {f7c6c6b6-4142-4c82-8699-4a9d8183181b} {0b1818eb-bdc8-4865-964f-db8bf05cfd86} {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9186eac4-2f34-4f17-b940-6585d7869bcd} CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC CompileAsC true true true true {CB906E89-1313-4929-AFF7-86FBF1CC301F} Win32Proj pmembench 10.0.14393.0 Application true v140 NotSet Application false v140 false NotSet false $(SolutionDir)\examples\libpmemobj\hashmap;$(SolutionDir)\examples\libpmemobj\map;$(SolutionDir)\examples\libpmemobj\tree_map;$(SolutionDir)\common;$(SolutionDir)\test\unittest;$(SolutionDir)\windows\include;$(SolutionDir)\libpmemobj\;$(SolutionDir)\include;$(SolutionDir)\libpmemblk;$(SolutionDir)\windows\getopt;$(IncludePath) false $(SolutionDir)\examples\libpmemobj\hashmap;$(SolutionDir)\examples\libpmemobj\map;$(SolutionDir)\examples\libpmemobj\tree_map;$(SolutionDir)\common;$(SolutionDir)\test\unittest;$(SolutionDir)\windows\include;$(SolutionDir)\libpmemobj\;$(SolutionDir)\include;$(SolutionDir)\libpmemblk;$(SolutionDir)\windows\getopt;$(IncludePath) NotUsing Level3 PMDK_UTF8_API;_CONSOLE;%(PreprocessorDefinitions) platform.h CompileAsCpp true false false 4200 Console DbgHelp.lib;Shlwapi.lib;%(AdditionalDependencies) false Debug 8000000 Level3 NotUsing true PMDK_UTF8_API;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) CompileAsCpp platform.h true 4200 Console DbgHelp.lib;Shlwapi.lib;%(AdditionalDependencies) false DebugFastLink 8000000 pmdk-1.4.1/src/benchmarks/pmembench.vcxproj.filters000066400000000000000000000130471331545616200224110ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {e2b109e4-df13-4e15-a231-6125a1c8de19} {eb18140e-4f6a-4d43-8f76-7ce1d000c8c8} pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj pmemobj Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files pmemobj Header Files Header Files Header Files Header Files Header Files Header Files Header Files pmdk-1.4.1/src/benchmarks/pmembench_atomic_lists.cfg000066400000000000000000000120751331545616200225600ustar00rootroot00000000000000# This is an example config file for pmembench # Global parameters [global] group = pmemobj file = testfile.list ops-per-thread = 10000 # obj_insert benchmark # variable number of threads # random type number, position and allocation size [obj_list_insert_threads] bench = obj_insert threads = 1:+1:10 data-size = 512 position = rand type-number = rand min-size = 1 # obj_insert benchmark # use circle queue from queue.h # variable number of threads # random type number, position and allocation size [queue_list_insert_threads] bench = obj_insert threads = 1:+1:10 data-size = 512 position = rand min-size = 1 queue = true # obj_insert benchmark # variable allocation size # insert tail # one type number per thread [obj_list_insert_data_size] bench = obj_insert threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread # obj_insert benchmark # use circle queue from queue.h # variable allocation size # insert tail # one type number per thread [queue_list_insert_data_size] bench = obj_insert threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread queue = true # obj_insert benchmark # variable number of threads # insert int the middle # one type-number [obj_list_insert_list_len] bench = obj_insert threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 # obj_insert benchmark # use circle queue from queue.h # variable number of threads # insert int the middle # one type-number [queue_list_insert_list_len] bench = obj_insert threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 queue = true # obj_insert_new benchmark # variable number of threads # random type number, position and allocation size [obj_list_insert_new_threads] bench = obj_insert_new threads = 1:+1:10 data-size = 512 position = rand type-number = rand min-size = 1 # obj_insert_new benchmark # variable allocation size # insert tail # one type number per thread [obj_list_insert_new_data_size] bench = obj_insert_new threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread # obj_insert_new benchmark # variable number of threads # insert int the middle # one type-number [obj_list_insert_new_list_len] bench = obj_insert_new threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 # obj_remove benchmark # variable number of threads # random type number, position and allocation size [obj_list_remove_threads] bench = obj_remove threads = 1:+1:10 data-size = 512 position = rand type-number = rand min-size = 1 # obj_remove benchmark # use circle queue from queue.h # variable number of threads # random type number, position and allocation size [queue_list_remove_threads] bench = obj_remove threads = 1:+1:10 data-size = 512 position = rand type-number = rand min-size = 1 queue = true # obj_remove benchmark # variable allocation size # insert tail # one type number per thread [obj_list_remove_data_size] bench = obj_remove threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread # obj_remove benchmark # use circle queue from queue.h # variable allocation size # insert tail # one type number per thread [queue_list_remove_data_size] bench = obj_remove threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread queue = true # obj_remove benchmark # variable number of threads # insert int the middle # one type-number [obj_list_remove_list_len] bench = obj_remove threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 # obj_remove benchmark # use circle queue from queue.h # variable number of threads # insert int the middle # one type-number [queue_list_remove_list_len] bench = obj_remove threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 queue = true # obj_remove_free benchmark # variable number of threads # random type number, position and allocation size [obj_list_remove_free_threads] bench = obj_remove_free threads = 1:+1:10 data-size = 512 position = rand type-number = rand min-size = 1 # obj_remove_free benchmark # variable allocation size # insert tail # one type number per thread [obj_list_remove_free_data_size] bench = obj_remove_free threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread # obj_remove_free benchmark # variable number of threads # insert int the middle # one type-number [obj_list_remove_free_list_len] bench = obj_remove_free threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 # obj_move benchmark # variable number of threads # random type number, position and allocation size [obj_list_move_threads] bench = obj_move threads = 1:+1:10 data-size = 512 position = rand type-number = rand min-size = 1 # obj_move benchmark # variable allocation size # insert tail # one type number per thread [obj_list_move_data_size] bench = obj_move threads = 1 data-size = 2:*2:8192 position = tail type-number = per-thread # obj_move benchmark # variable number of threads # insert int the middle # one type-number [obj_list_move_list_len] bench = obj_move threads = 1:+1:10 data-size = 512 position = middle type-number = one list-len = 1000 pmdk-1.4.1/src/benchmarks/pmembench_blk.cfg000066400000000000000000000034611331545616200206350ustar00rootroot00000000000000# Global parameters [global] group = pmemblk file = testfile.blk ops-per-thread=1000 # blk_read benchmark using blk with variable number of threads # from 1 to 32 [blk_blk_read_threads] bench = blk_read mode = rand operation = blk file-size = 536870912 threads = 1:+1:32 data-size = 512 # blk_read benchmark without using blk with variable number of threads # from 1 to 32 [blk_non_blk_read_threads] bench = blk_read mode = rand operation = file file-size = 536870912 threads = 1:+1:32 data-size = 512 # blk_read benchmark using blk with variable data size (block size) # from 512 to 1048576 bytes [blk_blk_read_data_size] bench = blk_read mode = rand operation = blk threads = 1 data-size = 512:*2:524288 file-size = 536870912 # blk_read benchmark without using blk with variable data size # from 512 to 1048576 bytes [blk_non_blk_read_data_size] bench = blk_read mode = rand operation = file threads = 1 data-size = 512:*2:524288 file-size = 536870912 # blk_write benchmark using blk with variable number of threads # from 1 to 32 [blk_blk_write_threads] bench = blk_write mode = rand operation = blk file-size = 536870912 threads = 1:+1:32 data-size = 512 # blk_write benchmark without using blk with variable number of threads # from 1 to 32 [blk_non_blk_write_threads] bench = blk_write mode = rand operation = file file-size = 536870912 threads = 1:+1:32 data-size = 512 # blk_write benchmark using blk with variable data size (block size) # from 512 to 1048576 bytes [blk_blk_write_data_size] bench = blk_write mode = seq operation = blk threads = 1 data-size = 512:*2:524288 file-size = 536870912 # blk_write benchmark without using blk with variable data size # from 512 to 1048576 bytes [blk_non_blk_write_data_size] bench = blk_write mode = seq operation = file threads = 1 data-size = 512:*2:524288 file-size = 536870912 pmdk-1.4.1/src/benchmarks/pmembench_flush.cfg000066400000000000000000000020411331545616200211770ustar00rootroot00000000000000# # pmembench_flush.cfg -- this is an example config file for pmembench # with scenarios for pmem_persist & pmem_msync benchmark # # Global parameters [global] group = pmem file = testfile.flush ops-per-thread = 100000 repeats = 3 threads = 1:*2:16 data-size = 64:*2:8192 mode = rand no-warmup = false [flush_noop] bench = pmem_flush operation = noop [flush_persist] bench = pmem_flush operation = persist [flush_persist_4K] bench = pmem_flush operation = persist_4K [flush_persist_2M] bench = pmem_flush operation = persist_2M [flush_persist_4K_msync_0] bench = pmem_flush operation = persist_4K_msync_0 [flush_persist_2M_msync_0] bench = pmem_flush operation = persist_2M_msync_0 [flush_msync] bench = pmem_flush operation = msync [flush_msync_0] bench = pmem_flush operation = msync_0 [flush_msync_async] bench = pmem_flush operation = msync_async [flush_msync_err] bench = pmem_flush operation = msync_err [flush_msync_invalid] bench = pmem_flush operation = msync_invalid [flush_msync_nodirty] bench = pmem_flush operation = msync_nodirty pmdk-1.4.1/src/benchmarks/pmembench_log.cfg000066400000000000000000000031361331545616200206450ustar00rootroot00000000000000# # pmembench_log.cfg -- this is an example config file for pmembench # with scenarios for pmemlog benchmark # # Global parameters [global] group = pmemlog file = testfile.log ops-per-thread = 1000 # log_append benchmark with variable number of threads [log_append_threads] bench = log_append threads = 1:+1:31 data-size = 512 # log_append benchmark with variable data sizes # from 32 to 8k bytes [log_append_data_size_huge] bench = log_append threads = 1 data-size = 32:*2:8192 min-size = 16 random = true seed = 1 # log_append benchmark with variable data sizes # from 1 to 32 bytes [log_append_data_size_small] bench = log_append threads = 1 data-size = 2:+1:32 min-size = 1 random = true seed = 1 # log_read benchmark with variable data sizes [log_read_variable_chunk_sizes] bench = log_read threads = 1 data-size = 64:*2:8192 # log_append benchmark with multiple threads and variable # vector sizes [log_append_threads_vector] bench = log_append threads = 8 data-size = 512 vector = 2:*2:32 # log_append benchmark with multiple threads, variable # vector sizes and random sizes [log_append_threads_random_vector] bench = log_append threads = 8 data-size = 512 random = true min-size = 32 vector = 2:*2:32 # fileio benchmark with multiple threads and variable # vector sizes [fileio_append_threads_vector] bench = log_append file-io = true threads = 8 data-size = 512 vector = 2:*2:32 # log_append benchmark with multiple threads, variable # vector sizes and random sizes [fileio_append_threads_random_vector] bench = log_append file-io = true threads = 8 data-size = 512 random = true min-size = 32 vector = 2:*2:32 pmdk-1.4.1/src/benchmarks/pmembench_map.cfg000066400000000000000000000003451331545616200206400ustar00rootroot00000000000000[global] group = pmemobj file = testfile.map ops-per-thread=1000000 threads=1 type = ctree,btree,rtree,rbtree,hashmap_atomic,hashmap_tx [map_insert] bench = map_insert [map_remove] bench = map_remove [map_get] bench = map_get pmdk-1.4.1/src/benchmarks/pmembench_memcpy.cfg000066400000000000000000000026701331545616200213600ustar00rootroot00000000000000# Global parameters [global] group = pmem file = testfile.memcpy ops-per-thread=50000 # pmem_memcpy benchmark with variable chunk sizes # from 64 to 8k bytes [pmcpy_chunk_sizes_aligned] bench = pmem_memcpy threads = 1 data-size = 64:*2:8192 # pmem_memcpy benchmark # with variable destination address offsets [pmcpy_destination_offsets] bench = pmem_memcpy threads = 1 data-size = 512 src-offset = 0 dest-offset = 1:+1:63 # pmem_memcpy pmem_memcpy_persist # copy mode: random # from 64 to 8k bytes [pmcpy_chunk_sizes_rand] bench = pmem_memcpy threads = 1 data-size = 64:*2:8192 src-mode = rand dest-mode = rand # pmem_memcpy pmem_memcpy_persist() # copy mode: sequential # from 64 to 8k bytes [pmcpy_pmem_memcpy_persist] bench = pmem_memcpy threads = 1 data-size = 64:*2:8192 libc-memcpy = false persist = true # pmem_memcpy pmem_memcpy_nodrain() # copy mode: sequential # from 64 to 8k bytes [pmcpy_pmem_memcpy_nodrain] bench = pmem_memcpy threads = 1 data-size = 64:*2:8192 libc-memcpy = false persist = false # pmem_memcpy standard memcpy() # followed by pmem_persist() # copy mode: sequential # from 64 to 8k bytes [pmcpy_libc_memcpy_persist] bench = pmem_memcpy threads = 1 data-size = 64:*2:8192 libc-memcpy = true persist = true # pmem_memcpy standard memcpy() # followed by pmem_flush() # copy mode: sequential # from 64 to 8k bytes [pmcpy_libc_memcpy_flush] bench = pmem_memcpy threads = 1 data-size = 64:*2:8192 libc-memcpy = true persist = false pmdk-1.4.1/src/benchmarks/pmembench_memset.cfg000066400000000000000000000036731331545616200213640ustar00rootroot00000000000000# # pmembench_memset.cfg -- this is an example config file for pmembench # with scenarios for pmem_memset benchmark # # Global parameters [global] group = pmem file = testfile.memset ops-per-thread = 10000 # memset benchmark with variable data sizes # from 1 to 32 bytes [pmem_memset_data_sizes_small] bench = pmem_memset threads = 1 data-size = 1:+1:32 # memset benchmark with variable data sizes # from 64 to 8k bytes # mode random [pmem_memset_data_sizes_rand] bench = pmem_memset threads = 1 data-size = 64:*2:8192 mem-mode = rand # memset benchmark with variable data sizes # from 64 to 8k bytes # offset 10 [pmem_memset_data_sizes_offset] bench = pmem_memset threads = 1 data-size = 64:*2:8192 dest-offset = 10 # memset benchmark with variable data sizes # from 64 to 8k bytes # mode sequential # pmem_memset_persist() [pmem_memset_pmem_memset_persist] bench = pmem_memset threads = 1 data-size = 64:*2:8192 memset = false persist = true mem-mode = seq # memset benchmark with variable data sizes # from 64 to 8k bytes # mode sequential # pmem_memset_nodrain() [pmem_memset_pmem_memset_nodrain] bench = pmem_memset threads = 1 data-size = 64:*2:8192 memset = false persist = false mem-mode = seq # memset benchmark with variable data sizes # from 64 to 8k bytes # mode sequential # memset followed by pmem_persist() [pmem_memset_libc_memset_persist] bench = pmem_memset threads = 1 data-size = 64:*2:8192 memset = true persist = true mem-mode = seq # memset benchmark with variable data sizes # from 64 to 8k bytes # mode sequential # memset followed by pmem_flush() [pmem_memset_libc_memset_flush] bench = pmem_memset threads = 1 data-size = 64:*2:8192 memset = true persist = false mem-mode = seq # memset benchmark with variable data sizes # from 64 to 8k bytes # mode sequential # memset followed by pmem_msync() [pmem_memset_libc_memset_persist] bench = pmem_memset threads = 1 data-size = 64:*2:8192 memset = true persist = false msync = true mem-mode = seq pmdk-1.4.1/src/benchmarks/pmembench_obj_gen.cfg000066400000000000000000000017511331545616200214700ustar00rootroot00000000000000# This is an example config file for pmembench # Global parameters [global] group = pmemobj file = testfile.obj ops-per-thread = 100 [obj_open_sizes] bench = obj_open data-size = 2:*2:1024 min-size = 1 objects = 10000 type-number = rand [obj_open_objects] bench = obj_open data-size = 1024 objects = 1:*10:100000 type-number = rand [obj_open_threads] bench = obj_open threads = 1:+1:10 data-size = 1024 min-size = 1 objects = 1000 type-number = rand [obj_direct_threads_one_pool] bench = obj_direct threads = 1:+1:10 data-size = 1024 min-size = 1 type-number = rand one-pool = true [obj_direct_threads_many_pools] bench = obj_direct threads = 1:+1:10 data-size = 1024 min-size = 1 type-number = rand [obj_direct_data_one_pool_one_obj] bench = obj_direct data-size = 2:*2:8192 type-number = rand one-pool = true one-object = true ops-per-thread = 10000 [obj_direct_threads_many_pools_one_obj] bench = obj_direct data-size = 2:*2:8192 type-number = rand one-object = true ops-per-thread = 10000 pmdk-1.4.1/src/benchmarks/pmembench_obj_lanes.cfg000066400000000000000000000004371331545616200220210ustar00rootroot00000000000000# Global parameters [global] group = pmemobj file = ./testfile.lane ops-per-thread = 100000 threads = 1:*2:32 [allocator_lane] bench = obj_lanes lane_section = allocator [list_lane] bench = obj_lanes lane_section = list [transaction_lane] bench = obj_lanes lane_section = transaction pmdk-1.4.1/src/benchmarks/pmembench_obj_locks.cfg000066400000000000000000000120321331545616200220240ustar00rootroot00000000000000# Global parameters [global] group = pmemobj file = ./testfile.locks ops-per-thread = 1000000:*10:10000000 # Single mutex benchmarks [single_pmem_locks] bench = obj_locks [single_pmem_locks_uninitialized] bench = obj_locks run_id = true run_id_init_val = 4 [single_system_mutex] bench = obj_locks use_system_threads = true # Multiple mutex benchmarks - 1by1 [multiple_pmem_locks_locked_once_1by1] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 [multiple_pmem_locks_uninitialized_locked_once_1by1] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 run_id_init_val = 4 [multiple_system_mutex_locked_once_1by1] bench = obj_locks ops-per-thread = 1 use_system_threads = true numlocks = 1000000:*10:10000000 [multiple_pmem_locks_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 [multiple_pmem_locks_uninitialized_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 run_id = true run_id_init_val = 4 [multiple_system_mutex_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 use_system_threads = true # Multiple mutex benchmarks - all-lock [multiple_pmem_locks_locked_once_alllock] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 mode = all-lock [multiple_pmem_locks_uninitialized_locked_once_alllock] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 mode = all-lock run_id = true run_id_init_val = 4 [multiple_system_mutex_locked_once_alllock] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 use_system_threads = true mode = all-lock [multiple_pmem_locks_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 mode = all-lock [multiple_pmem_locks_uninitialized_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 run_id = true run_id_init_val = 4 mode = all-lock [multiple_system_mutex_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 use_system_threads = true mode = all-lock #rwlock benchmarks [single_pmem_wrlock] bench = obj_locks bench_type = rwlock [single_pmem_rdlock] bench = obj_locks bench_type = rwlock rdlock = true [single_system_wrlock] bench = obj_locks bench_type = rwlock use_system_threads = true [single_system_rdlock] bench = obj_locks bench_type = rwlock rdlock = true use_system_threads = true [multiple_pmem_wrlock_locked_once_1by1] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 bench_type = rwlock [multiple_pmem_wrlock_uninitialized_locked_once_1by1] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 run_id_init_val = 4 bench_type = rwlock [multiple_system_wrlock_locked_once_1by1] bench = obj_locks ops-per-thread = 1 use_system_threads = true numlocks = 1000000:*10:10000000 bench_type = rwlock [multiple_pmem_wrlock_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 bench_type = rwlock [multiple_pmem_wrlock_uninitialized_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 run_id = true run_id_init_val = 4 bench_type = rwlock [multiple_system_wrlock_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 use_system_threads = true bench_type = rwlock [multiple_pmem_wrlock_locked_once_alllock] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 bench_type = rwlock mode = all-lock [multiple_pmem_wrlock_uninitialized_locked_once_alllock] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 run_id_init_val = 4 bench_type = rwlock mode = all-lock [multiple_system_wrlock_locked_once_alllock] bench = obj_locks ops-per-thread = 1 use_system_threads = true numlocks = 1000000:*10:10000000 bench_type = rwlock mode = all-lock [multiple_pmem_wrlock_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 bench_type = rwlock mode = all-lock [multiple_pmem_wrlock_uninitialized_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 run_id = true run_id_init_val = 4 bench_type = rwlock mode = all-lock [multiple_system_wrlock_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 use_system_threads = true bench_type = rwlock mode = all-lock # volatile mutex - only for testing # it is an alternate implementation of PMEMmutex, which keeps # the system mutex in RAM [single_volatile_mutex] bench = obj_locks bench_type = volatile-mutex [multiple_volatile_mutex_locked_once_1by1] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 bench_type = volatile-mutex [multiple_volatile_mutex_1by1] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 bench_type = volatile-mutex [multiple_volatile_mutex_locked_once_alllock] bench = obj_locks ops-per-thread = 1 numlocks = 1000000:*10:10000000 mode = all-lock bench_type = volatile-mutex [multiple_volatile_mutex_alllock] bench = obj_locks numlocks = 10000:*10:100000 ops-per-thread = 10000:/10:100 mode = all-lock bench_type = volatile-mutex pmdk-1.4.1/src/benchmarks/pmembench_obj_persist.cfg000066400000000000000000000007351331545616200224110ustar00rootroot00000000000000# # pmembench_obj_persist.cfg -- this is an example config file for pmembench # with scenarios for pmemobj_persist() benchmark # # Global parameters [global] group = obj_persist file = testfile.obj_persist ops-per-thread = 10000 [pmemobj_persist_DS8] bench = pmemobj_persist threads = 1:+1:32 data-size = 8 [pmemobj_persist_DS512] bench = pmemobj_persist threads = 1:+1:32 data-size = 512 [pmemobj_persist_DS1024] bench = pmemobj_persist threads = 1:+1:32 data-size = 1024 pmdk-1.4.1/src/benchmarks/pmembench_obj_pmalloc.cfg000066400000000000000000000010741331545616200223440ustar00rootroot00000000000000# Global parameters [global] group = pmemobj file = ./testfile.pmalloc ops-per-thread = 1000 data-size = 4096 threads = 1 #Single thread benchmarks [pmalloc_single_thread_size] bench = pmalloc data-size = 64:*2:262144 [pmalloc_single_thread_ops] bench = pmalloc ops-per-thread = 10:*10:100000 [pfree_single_thread_size] bench = pfree data-size = 64:*2:262144 [pfree_single_thread_ops] bench = pfree ops-per-thread = 10:*10:100000 #Multithreaded benchmarks [pmalloc_multi_thread] bench = pmalloc threads = 2:*2:32 [pfree_multi_thread] bench = pfree threads = 2:*2:32 pmdk-1.4.1/src/benchmarks/pmembench_rpmem.cfg000066400000000000000000000006731331545616200212070ustar00rootroot00000000000000# # pmembench_rpmem.cfg -- this is an example config file for pmembench # with scenarios for rpmem benchmark # # Global parameters [global] group = rpmem file = testfile.poolset.rpmem ops-per-thread = 10000 [rpmem_persist_DS8] bench = rpmem_persist threads = 1:+1:32 data-size = 8 [rpmem_persist_DS512] bench = rpmem_persist threads = 1:+1:32 data-size = 512 [rpmem_persist_DS1024] bench = rpmem_persist threads = 1:+1:32 data-size = 1024 pmdk-1.4.1/src/benchmarks/pmembench_tx.cfg000066400000000000000000000177151331545616200205270ustar00rootroot00000000000000# This is an example config file for pmembench # Global parameters [global] file = /dev/shm/testfile.tx group = pmemobj ops-per-thread = 100 # obj_tx_alloc benchmark # variable threads number # one type-number [obj_tx_alloc_thread_one_type_num] bench = obj_tx_alloc threads = 1:+1:5 data-size = 512 # obj_tx_alloc benchmark # variable threads number # one type-number per thread [obj_tx_alloc_thread_per_thread_type_num] bench = obj_tx_alloc threads = 1:+1:5 data-size = 512 type-number = per-thread # obj_tx_alloc benchmark # variable allocation size # abort every nested transaction # rand type-number [obj_tx_alloc_sizes_abort_nested] bench = obj_tx_alloc data-size = 8:*2:16384 operation = abort-nested nestings = 100 type-number = rand # obj_tx_alloc benchmark # variable allocation size # use file io instead pmem # rand type-number [obj_tx_alloc_sizes_file_io] bench = obj_tx_alloc data-size = 8:*2:16384 nestings = 100 lib = dram type-number = rand # obj_tx_alloc benchmark # variable allocation size # pmem without transactions # rand type-number [obj_tx_alloc_sizes_atomic] bench = obj_tx_alloc data-size = 8:*2:16384 nestings = 100 lib = pmem type-number = rand # obj_tx_alloc benchmark # variable number of nested transactions # abort every nested transaction # rand type-number [obj_tx_alloc_nestings_abort_nested] bench = obj_tx_alloc data-size = 512 min-size = 1 operation = abort-nested nestings = 1:*10:10000 type-number = rand # obj_tx_alloc benchmark # variable number of nested transactions # use file io instead pmem # rand type-number [obj_tx_alloc_nestings_file_io] bench = obj_tx_alloc data-size = 512 min-size = 1 nestings = 1:*10:10000 lib = dram type-number = rand # obj_tx_alloc benchmark # variable number of nested transactions # pmem without transactions # rand type-number [obj_tx_alloc_nestings_atomic] bench = obj_tx_alloc data-size = 512 min-size = 1 nestings = 1:*10:10000 lib = pmem type-number = rand # obj_tx_free benchmark # variable allocation size # abort every nested transaction # rand type-number [obj_tx_free_sizes_abort_nested] bench = obj_tx_free data-size = 8:*2:8192 operation = abort-nested nestings = 100 type-number = rand # obj_tx_free benchmark # variable allocation size # use file io instead pmem # rand type-number [obj_tx_free_sizes_file_io] bench = obj_tx_free data-size = 8:*2:8192 nestings = 100 lib = dram type-number = rand # obj_tx_free benchmark # variable allocation size # pmem without transactions # rand type-number [obj_tx_free_sizes_atomic] bench = obj_tx_free data-size = 8:*2:8192 nestings = 100 lib = pmem type-number = rand # obj_tx_free benchmark # variable number of nested transactions # abort every nested transaction # rand type-number [obj_tx_free_nestings_abort_nested] bench = obj_tx_free data-size = 512 min-size = 1 operation = abort-nested nestings = 1:*10:10000 type-number = rand # obj_tx_free benchmark # variable number of nested transactions # use file io instead pmem # rand type-number [obj_tx_free_nestings_file_io] bench = obj_tx_free data-size = 512 min-size = 1 nestings = 1:*10:10000 lib = dram type-number = rand # obj_tx_free benchmark # variable number of nested transactions # pmem without transactions # rand type-number [obj_tx_free_nestings_atomic] bench = obj_tx_free data-size = 512 min-size = 1 nestings = 1:*10:10000 lib = pmem type-number = rand # obj_tx_realloc benchmark # variable allocation size # abort every nested transaction # rand type-number [obj_tx_realloc_data_sizes_abort] bench = obj_tx_realloc data-size = 8:*2:8192 realloc-size = 64 min-rsize = 1 operation = abort nestings = 100 type-number = rand # obj_tx_realloc benchmark # variable allocation size # use file io instead pmem # rand type-number [obj_tx_realloc_data_sizes_file_io] bench = obj_tx_realloc data-size = 8:*2:8192 realloc-size = 64 min-rsize = 1 nestings = 100 lib = dram type-number = rand # obj_tx_realloc benchmark # variable allocation size # pmem without transactions # rand type-number [obj_tx_realloc_data_sizes_atomic] bench = obj_tx_realloc data-size = 8:*2:8192 realloc-size = 64 min-rsize = 1 nestings = 100 lib = pmem type-number = rand # obj_tx_realloc benchmark # variable reallocation size # abort every nested transaction # rand type-number # another type number in realloc than in alloc [obj_tx_realloc_sizes_abort] bench = obj_tx_realloc data-size = 4 min-size = 1 realloc-size = 256:*2:16384 operation = abort changed-type = true type-number = rand # obj_tx_realloc benchmark # variable reallocation size # use file io instead pmem # rand type-number [obj_tx_realloc_sizes_file_io] bench = obj_tx_realloc data-size = 4 min-size = 1 realloc-size = 256:*2:16384 lib = dram type-number = rand # obj_tx_realloc benchmark # variable reallocation size # abort every nested transaction # rand type-number # another type number in realloc than in alloc [obj_tx_realloc_sizes_atomic] bench = obj_tx_realloc data-size = 4 min-size = 1 realloc-size = 256:*2:16384 lib = pmem changed-type = true type-number = rand # obj_tx_add_range benchmark # variable allocation size # allocate different objects # in one transaction # rand type-number [obj_tx_add_sizes_all_obj] bench = obj_tx_add_range data-size = 128:*2:16384 operation = all-obj type-number = rand # obj_tx_add_range benchmark # variable operations number # allocate different objects # in one transaction # rand type-number [obj_tx_add_ops_all_obj] bench = obj_tx_add_range data-size = 512 operation = all-obj ops-per-thread = 1:*5:625 type-number = rand # obj_tx_add_range benchmark # variable allocation size # allocate one object # in one transaction # rand type-number [obj_tx_add_sizes_one_obj] bench = obj_tx_add_range data-size = 128:*2:16384 operation = basic type-number = rand # obj_tx_add_range benchmark # variable operations number # allocate one object # in one transaction # rand type-number [obj_tx_add_ops_one_obj] bench = obj_tx_add_range data-size = 10000 operation = basic ops-per-thread = 1:*5:78125 type-number = rand # obj_tx_add_range benchmark # variable allocation size # allocate parts of one object # in one transaction # rand type-number [obj_tx_add_sizes_range] bench = obj_tx_add_range data-size = 128:*2:16384 operation = range type-number = rand # obj_tx_add_range benchmark # variable operations number # allocate parts of one object # in one transaction # rand type-number [obj_tx_add_ops_range] bench = obj_tx_add_range data-size = 10000 operation = range ops-per-thread = 1:*5:625 type-number = rand # obj_tx_add_range benchmark # variable allocation size # allocate all objects # in many nested transactions # rand type-number [obj_tx_add_sizes_all_obj_nested] bench = obj_tx_add_range data-size = 128:*2:16384 operation = all-obj-nested type-number = rand # obj_tx_add_range benchmark # variable operations number # allocate all objects # in many nested transactions # rand type-number [obj_tx_add_ops_all_obj_nested] bench = obj_tx_add_range data-size = 10000 operation = all-obj-nested ops-per-thread = 1:*5:625 type-number = rand # obj_tx_add_range benchmark # variable allocation size # allocate one object # in many nested transactions # rand type-number [obj_tx_add_sizes_one_obj_nested] bench = obj_tx_add_range data-size = 128:*2:16384 operation = one-obj-nested type-number = rand # obj_tx_add_range benchmark # variable operations number # allocate one object # in many nested transactions # rand type-number [obj_tx_add_ops_one_obj_nested] bench = obj_tx_add_range data-size = 10000 operation = one-obj-nested ops-per-thread = 1:*5:625 type-number = rand # obj_tx_add_range benchmark # variable allocation size # allocate parts of one object # in many nested transactions # rand type-number [obj_tx_add_sizes_range_nested] bench = obj_tx_add_range data-size = 128:*2:16384 operation = range-nested type-number = rand # obj_tx_add_range benchmark # variable operations number # allocate parts of one objects # in many nested transactions # rand type-number [obj_tx_add_ops_range_nested] bench = obj_tx_add_range data-size = 10000 operation = range-nested ops-per-thread = 1:*5:625 type-number = rand pmdk-1.4.1/src/benchmarks/pmembench_vmem.cfg000066400000000000000000000144751331545616200210400ustar00rootroot00000000000000# This is an example config file for pmembench # Global parameters [global] group = vmem file = testdir.vmem ops-per-thread = 100000 # vmem_malloc benchmark # vmem allocator # range allocation # variable number of threads # creating one pool per thread [vmem_range_ppt_threads_malloc] bench = vmem_malloc stdlib-alloc = false threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true # vmem_malloc benchmark # no-vmem allocator # range allocation # variable number of threads # creating one pool per thread [novmem_range_ppt_threads_malloc] bench = vmem_malloc stdlib-alloc = true threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true # vmem_free benchmark # vmem allocator # range allocation # variable number of threads # creating one pool per thread [vmem_range_ppt_threads_free] bench = vmem_free stdlib-alloc = false threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true # vmem_free benchmark # no-vmem allocator # range allocation # variable number of threads # creating one pool per thread [novmem_range_ppt_threads_free] bench = vmem_free stdlib-alloc = true threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true # vmem_free benchmark # vmem allocator # range allocation # variable number of threads # creating one pool per thread # frees memory allocated by another thread [vmem_range_ppt_mix_threads_free] bench = vmem_free stdlib-alloc = false threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true mix-thread = true # vmem_free benchmark # no-vmem allocator # range allocation # variable number of threads # creating one pool per thread # frees memory allocated by another thread [novmem_range_ppt_mix_threads_free] bench = vmem_free stdlib-alloc = true threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true mix-thread = true # vmem_malloc benchmark # vmem allocator # variable data size [vmem_sizes_malloc] bench = vmem_malloc stdlib-alloc = false data-size = 2:*2:16777216 ops-per-thread = 5 threads = 16 # vmem_malloc benchmark # no-vmem allocator # variable data size [novmem_sizes_malloc] bench = vmem_malloc stdlib-alloc = true data-size = 2:*2:16777216 ops-per-thread = 5 threads = 16 # vmem_free benchmark # vmem allocator # variable data size [vmem_sizes_free] bench = vmem_free stdlib-alloc = false data-size = 2:*2:16777216 ops-per-thread = 5 threads = 16 # vmem_free benchmark # no-vmem allocator # variable data size [novmem_sizes_free] bench = vmem_free stdlib-alloc = true data-size = 2:*2:16777216 ops-per-thread = 5 threads = 16 # vmem_free benchmark # vmem allocator # variable data size # frees memory allocated by another thread [vmem_sizes_mix_threads_free] bench = vmem_free stdlib-alloc = false data-size = 2:*2:16777216 ops-per-thread = 5 no-warmup = true mix-thread = true threads = 16 # vmem_free benchmark # no-vmem allocator # variable data size # frees memory allocated by another thread [novmem_sizes_mix_threads_free] bench = vmem_free stdlib-alloc = true data-size = 2:*2:16777216 ops-per-thread = 5 mix-thread = true threads = 16 # vmem_mix benchmark # vmem allocator # range allocation # variable number of threads # creating one pool per thread [vmem_range_ppt_threads_mix] bench = vmem_mix stdlib-alloc = false threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true # vmem_mix benchmark # no-vmem allocator # range allocation # variable number of threads # creating one pool per thread [novmem_range_ppt_threads_mix] bench = vmem_mix stdlib-alloc = true threads = 1:+1:8 data-size = 2048 alloc-min = 0 seed = 1234 pool-per-thread = true # vmem_mix benchmark # vmem allocator # variable data size [vmem_sizes_mix] bench = vmem_mix stdlib-alloc = false data-size = 2:*2:16777216 threads = 16 ops-per-thread = 5 # vmem_mix benchmark # no-vmem allocator # variable data size [novmem_sizes_mix] bench = vmem_mix stdlib-alloc = true data-size = 2:*2:16777216 threads = 16 ops-per-thread = 5 # vmem_realloc benchmark # vmem allocator # range allocation and reallocation # variable number of threads # creating one pool per thread [vmem_range_ppt_threads_realloc] bench = vmem_realloc stdlib-alloc = false threads = 1:+1:8 data-size = 512 realloc-size = 2048 alloc-min = 0 realloc-min = 0 seed = 1234 pool-per-thread = true # vmem_mix benchmark # no-vmem allocator # range allocation and reallocation # variable number of threads # creating one pool per thread [novmem_range_ppt_threads_realloc] bench = vmem_realloc stdlib-alloc = true threads = 1:+1:8 data-size = 512 realloc-size = 2048 alloc-min = 0 realloc-min = 0 seed = 1234 pool-per-thread = true # vmem_realloc benchmark # vmem allocator # variable data size [vmem_sizes_realloc] bench = vmem_realloc stdlib-alloc = false data-size = 1048576 realloc-size = 1048576:/2:2 ops-per-thread = 100 # vmem_realloc benchmark # no-vmem allocator # variable data size [novmem_sizes_realloc] bench = vmem_realloc stdlib-alloc = true data-size = 1048576 realloc-size = 1048576:/2:2 ops-per-thread = 100 # vmem_realloc benchmark # vmem allocator # range allocation and reallocation # variable number of threads # creating one pool per thread # frees memory allocated by another thread [vmem_range_ppt_mix_threads_realloc] bench = vmem_realloc stdlib-alloc = false threads = 1:+1:8 data-size = 512 realloc-size = 2048 alloc-min = 0 realloc-min = 0 seed = 1234 pool-per-thread = true mix-thread = true # vmem_mix benchmark # no-vmem allocator # range allocation and reallocation # variable number of threads # creating one pool per thread # frees memory allocated by another thread [novmem_range_ppt_mix_threads_realloc] bench = vmem_realloc stdlib-alloc = true threads = 1:+1:8 data-size = 512 realloc-size = 2048 alloc-min = 0 realloc-min = 0 seed = 1234 pool-per-thread = true mix-thread = true # vmem_realloc benchmark # vmem allocator # variable data size # frees memory allocated by another thread [vmem_sizes_mix_threads_realloc] bench = vmem_realloc stdlib-alloc = false data-size = 512 realloc-size = 1048576:/2:2 ops-per-thread = 100 mix-thread = true threads = 16 # vmem_realloc benchmark # no-vmem allocator # variable data size # frees memory allocated by another thread [novmem_sizes_mix_threads_realloc] bench = vmem_realloc stdlib-alloc = true data-size = 512 realloc-size = 1048576:/2:2 ops-per-thread = 100 mix-thread = true threads = 16 pmdk-1.4.1/src/benchmarks/pmemobj_atomic_lists.cpp000066400000000000000000001002511331545616200222700ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmemobj_atomic_lists.cpp -- benchmark for pmemobj atomic list API */ #include "benchmark.hpp" #include "libpmemobj.h" #include "queue.h" #include #include #include #include #include #include #include #define FACTOR 8 #define LAYOUT_NAME "benchmark" struct obj_bench; struct obj_worker; struct element; TOID_DECLARE(struct item, 0); TOID_DECLARE(struct list, 1); typedef size_t (*fn_type_num_t)(size_t worker_idx, size_t op_idx); typedef struct element (*fn_position_t)(struct obj_worker *obj_worker, size_t op_idx); typedef int (*fn_init_t)(struct worker_info *worker, size_t n_elm, size_t list_len); /* * args -- stores command line parsed arguments. */ struct obj_list_args { char *type_num; /* type_number mode - one, per-thread, rand */ char *position; /* position - head, tail, middle, rand */ unsigned list_len; /* initial list length */ bool queue; /* use circle queue from */ bool range; /* use random allocation size */ unsigned min_size; /* minimum random allocation size */ unsigned seed; /* seed value */ }; /* * obj_bench -- stores variables used in benchmark, passed within functions. */ static struct obj_bench { /* handle to persistent pool */ PMEMobjpool *pop; /* pointer to benchmark specific arguments */ struct obj_list_args *args; /* array to store random type_number values */ size_t *random_types; /* * fn_rpositions array stores random functions returning proper element * from list, if position where operation is performed is random. * Possible function which can be in array are: * - position_head, * - position_tail, * - position_middle. */ size_t *alloc_sizes; /* array to store random sizes of each object */ size_t max_len; /* maximum list length */ size_t min_len; /* initial list length */ int type_mode; /* type_number mode */ int position_mode; /* list destination mode */ /* * fn_type_num gets proper function assigned, depending on the * value of the type_mode argument, which returns proper type number for * each persistent object. Possible functions are: * - type_mode_one, * - type_mode_per_thread, * - type_mode_rand. */ fn_type_num_t fn_type_num; /* * fn_position gets proper function assigned, depending on the value * of the position argument, which returns handle to proper element on * the list. Possible functions are: * - position_head, * - position_tail, * - position_middle, * - position_rand. */ fn_position_t fn_position; /* * fn_init gets proper function assigned, depending on the file_io * flag, which allocates objects and initializes proper list. Possible * functions are: * - obj_init_list, * - queue_init_list. */ fn_init_t fn_init; } obj_bench; /* * item -- structure used to connect elements in lists. */ struct item { POBJ_LIST_ENTRY(struct item) field; CIRCLEQ_ENTRY(item) fieldq; }; /* * element -- struct contains one item from list with proper type. */ struct element { struct item *itemq; TOID(struct item) itemp; bool before; }; /* * obj_worker -- stores variables used by one thread, concerning one list. */ struct obj_worker { /* head of the pmemobj list */ POBJ_LIST_HEAD(plist, struct item) head; /* head of the circular queue */ CIRCLEQ_HEAD(qlist, item) headq; TOID(struct item) * oids; /* persistent pmemobj list elements */ struct item **items; /* volatile elements */ size_t n_elm; /* number of elements in array */ fn_position_t *fn_positions; /* element access functions */ struct element elm; /* pointer to current element */ /* * list_move is a pointer to structure storing variables used by * second list (used only for obj_move benchmark). */ struct obj_worker *list_move; }; /* * position_mode -- list destination type */ enum position_mode { /* object inserted/removed/moved to/from head of list */ POSITION_MODE_HEAD, /* object inserted/removed/moved to/from tail of list */ POSITION_MODE_TAIL, /* * object inserted/removed/moved to/from second element of the list * or to/from head if list length equal to one */ POSITION_MODE_MIDDLE, /* object inserted/removed/moved to/from head, tail or middle */ POSITION_MODE_RAND, POSITION_MODE_UNKNOWN, }; /* * type_mode -- type number type */ enum type_mode { TYPE_MODE_ONE, /* one type number for all of objects */ /* one type number for objects allocated by the same thread */ TYPE_MODE_PER_THREAD, TYPE_MODE_RAND, /* random type number for each object */ TYPE_MODE_UNKNOWN, }; /* * position_head -- returns head of the persistent list or volatile queue. */ static struct element position_head(struct obj_worker *obj_worker, size_t op_idx) { struct element head = {0, OID_NULL, false}; head.before = true; if (!obj_bench.args->queue) head.itemp = POBJ_LIST_FIRST(&obj_worker->head); else head.itemq = CIRCLEQ_FIRST(&obj_worker->headq); return head; } /* * position_tail -- returns tail of the persistent list or volatile queue. */ static struct element position_tail(struct obj_worker *obj_worker, size_t op_idx) { struct element tail = {0, OID_NULL, false}; tail.before = false; if (!obj_bench.args->queue) tail.itemp = POBJ_LIST_LAST(&obj_worker->head, field); else tail.itemq = CIRCLEQ_LAST(&obj_worker->headq); return tail; } /* * position_middle -- returns second or first element from the persistent list * or volatile queue. */ static struct element position_middle(struct obj_worker *obj_worker, size_t op_idx) { struct element elm = position_head(obj_worker, op_idx); elm.before = true; if (!obj_bench.args->queue) elm.itemp = POBJ_LIST_NEXT(elm.itemp, field); else elm.itemq = CIRCLEQ_NEXT(elm.itemq, fieldq); return elm; } /* * position_rand -- returns first, second or last element from the persistent * list or volatile queue based on r_positions array. */ static struct element position_rand(struct obj_worker *obj_worker, size_t op_idx) { struct element elm; elm = obj_worker->fn_positions[op_idx](obj_worker, op_idx); elm.before = true; return elm; } /* * type_mode_one -- always returns 0, as in the mode TYPE_MODE_ONE * all of the persistent objects have the same type_number value. */ static size_t type_mode_one(size_t worker_idx, size_t op_idx) { return 0; } /* * type_mode_per_thread -- always returns the index of the worker, * as in the TYPE_MODE_PER_THREAD the value of the persistent object * type_number is specific to the thread. */ static size_t type_mode_per_thread(size_t worker_idx, size_t op_idx) { return worker_idx; } /* * type_mode_rand -- returns the value from the random_types array assigned * for the specific operation in a specific thread. */ static size_t type_mode_rand(size_t worker_idx, size_t op_idx) { return obj_bench.random_types[op_idx]; } const char *type_num_names[] = {"one", "per-thread", "rand"}; const char *position_names[] = {"head", "tail", "middle", "rand"}; static fn_type_num_t type_num_modes[] = {type_mode_one, type_mode_per_thread, type_mode_rand}; static fn_position_t positions[] = {position_head, position_tail, position_middle, position_rand}; /* function pointers randomly picked when using rand mode */ static fn_position_t rand_positions[] = {position_head, position_tail, position_middle}; /* * get_item -- common part of initial operation of the all benchmarks. * It gets pointer to element on the list where object will * be inserted/removed/moved to/from. */ static void get_item(struct benchmark *bench, struct operation_info *info) { struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; obj_worker->elm = obj_bench.fn_position(obj_worker, info->index); } /* * get_move_item -- special part of initial operation of the obj_move * benchmarks. It gets pointer to element on the list where object will be * inserted/removed/moved to/from. */ static int get_move_item(struct benchmark *bench, struct operation_info *info) { struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; obj_worker->list_move->elm = obj_bench.fn_position(obj_worker->list_move, info->index); get_item(bench, info); return 0; } /* * parse_args -- parse command line string argument */ static int parse_args(char *arg, int max, const char **names) { int i = 0; for (; i < max && strcmp(names[i], arg) != 0; i++) ; if (i == max) fprintf(stderr, "Invalid argument\n"); return i; } /* * obj_init_list -- special part of worker initialization, performed only if * queue flag set false. Allocates proper number of items, and inserts proper * part of them to the pmemobj list. */ static int obj_init_list(struct worker_info *worker, size_t n_oids, size_t list_len) { size_t i; struct obj_worker *obj_worker = (struct obj_worker *)worker->priv; obj_worker->oids = (TOID(struct item) *)calloc(n_oids, sizeof(TOID(struct item))); if (obj_worker->oids == NULL) { perror("calloc"); return -1; } for (i = 0; i < n_oids; i++) { size_t type_num = obj_bench.fn_type_num(worker->index, i); size_t size = obj_bench.alloc_sizes[i]; PMEMoid *tmp = (PMEMoid *)&obj_worker->oids[i]; if (pmemobj_alloc(obj_bench.pop, tmp, size, type_num, NULL, NULL) != 0) goto err_oids; } for (i = 0; i < list_len; i++) POBJ_LIST_INSERT_TAIL(obj_bench.pop, &obj_worker->head, obj_worker->oids[i], field); return 0; err_oids: for (; i > 0; i--) POBJ_FREE(&obj_worker->oids[i - 1]); free(obj_worker->oids); return -1; } /* * queue_init_list -- special part of worker initialization, performed only if * queue flag set. Initiates circle queue, allocates proper number of items and * inserts proper part of them to the queue. */ static int queue_init_list(struct worker_info *worker, size_t n_items, size_t list_len) { size_t i; struct obj_worker *obj_worker = (struct obj_worker *)worker->priv; CIRCLEQ_INIT(&obj_worker->headq); obj_worker->items = (struct item **)malloc(n_items * sizeof(struct item *)); if (obj_worker->items == NULL) { perror("malloc"); return -1; } for (i = 0; i < n_items; i++) { size_t size = obj_bench.alloc_sizes[i]; obj_worker->items[i] = (struct item *)calloc(1, size); if (obj_worker->items[i] == NULL) { perror("calloc"); goto err; } } for (i = 0; i < list_len; i++) CIRCLEQ_INSERT_TAIL(&obj_worker->headq, obj_worker->items[i], fieldq); return 0; err: for (; i > 0; i--) free(obj_worker->items[i - 1]); free(obj_worker->items); return -1; } /* * queue_free_worker_list -- special part for the worker de-initialization when * queue flag is true. Releases items directly from atomic list. */ static void queue_free_worker_list(struct obj_worker *obj_worker) { while (!CIRCLEQ_EMPTY(&obj_worker->headq)) { struct item *tmp = CIRCLEQ_LAST(&obj_worker->headq); CIRCLEQ_REMOVE(&obj_worker->headq, tmp, fieldq); free(tmp); } free(obj_worker->items); } /* * obj_free_worker_list -- special part for the worker de-initialization when * queue flag is false. Releases items directly from atomic list. */ static void obj_free_worker_list(struct obj_worker *obj_worker) { while (!POBJ_LIST_EMPTY(&obj_worker->head)) { TOID(struct item) tmp = POBJ_LIST_FIRST(&obj_worker->head); POBJ_LIST_REMOVE_FREE(obj_bench.pop, &obj_worker->head, tmp, field); } free(obj_worker->oids); } /* * obj_free_worker_items -- special part for the worker de-initialization when * queue flag is false. Releases items used for create pmemobj list. */ static void obj_free_worker_items(struct obj_worker *obj_worker) { for (size_t i = 0; i < obj_worker->n_elm; i++) POBJ_FREE(&obj_worker->oids[i]); free(obj_worker->oids); } /* * queue_free_worker_items -- special part for the worker de-initialization * when queue flag set. Releases used for create circle queue. */ static void queue_free_worker_items(struct obj_worker *obj_worker) { for (size_t i = 0; i < obj_worker->n_elm; i++) free(obj_worker->items[i]); free(obj_worker->items); } /* * random_positions -- allocates array and calculates random values for * defining positions where each operation will be performed. Used only * in POSITION_MODE_RAND */ static fn_position_t * random_positions(void) { fn_position_t *positions = (fn_position_t *)calloc( obj_bench.max_len, sizeof(fn_position_t)); if (positions == NULL) { perror("calloc"); return NULL; } if (obj_bench.args->seed != 0) srand(obj_bench.args->seed); size_t rmax = ARRAY_SIZE(rand_positions); for (size_t i = 0; i < obj_bench.max_len; i++) { size_t id = RRAND(rmax, 0); positions[i] = rand_positions[id]; } return positions; } /* * rand_values -- allocates array and if range mode calculates random * values as allocation sizes for each object otherwise populates whole array * with max value. Used only when range flag set. */ static size_t * random_values(size_t min, size_t max, size_t n_ops, size_t min_range) { size_t *randoms = (size_t *)calloc(n_ops, sizeof(size_t)); if (randoms == NULL) { perror("calloc"); return NULL; } for (size_t i = 0; i < n_ops; i++) randoms[i] = max; if (min > min_range) { if (min > max) { fprintf(stderr, "Invalid size\n"); free(randoms); return NULL; } for (size_t i = 0; i < n_ops; i++) randoms[i] = RRAND(max, min); } return randoms; } /* * queue_insert_op -- main operations of the obj_insert benchmark when queue * flag set to true. */ static int queue_insert_op(struct operation_info *info) { struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; CIRCLEQ_INSERT_AFTER(&obj_worker->headq, obj_worker->elm.itemq, obj_worker->items[info->index + obj_bench.min_len], fieldq); return 0; } /* * obj_insert_op -- main operations of the obj_insert benchmark when queue flag * set to false. */ static int obj_insert_op(struct operation_info *info) { struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; POBJ_LIST_INSERT_AFTER( obj_bench.pop, &obj_worker->head, obj_worker->elm.itemp, obj_worker->oids[info->index + obj_bench.min_len], field); return 0; } /* * queue_remove_op -- main operations of the obj_remove benchmark when queue * flag set to true. */ static int queue_remove_op(struct operation_info *info) { struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; CIRCLEQ_REMOVE(&obj_worker->headq, obj_worker->elm.itemq, fieldq); return 0; } /* * obj_remove_op -- main operations of the obj_remove benchmark when queue flag * set to false. */ static int obj_remove_op(struct operation_info *info) { struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; POBJ_LIST_REMOVE(obj_bench.pop, &obj_worker->head, obj_worker->elm.itemp, field); return 0; } /* * insert_op -- main operations of the obj_insert benchmark. */ static int insert_op(struct benchmark *bench, struct operation_info *info) { get_item(bench, info); return obj_bench.args->queue ? queue_insert_op(info) : obj_insert_op(info); } /* * obj_insert_new_op -- main operations of the obj_insert_new benchmark. */ static int obj_insert_new_op(struct benchmark *bench, struct operation_info *info) { get_item(bench, info); struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; PMEMoid tmp; size_t size = obj_bench.alloc_sizes[info->index]; size_t type_num = obj_bench.fn_type_num(info->worker->index, info->index); tmp = pmemobj_list_insert_new( obj_bench.pop, offsetof(struct item, field), &obj_worker->head, obj_worker->elm.itemp.oid, obj_worker->elm.before, size, type_num, NULL, NULL); if (OID_IS_NULL(tmp)) { perror("pmemobj_list_insert_new"); return -1; } return 0; } /* * remove_op -- main operations of the obj_remove benchmark. */ static int remove_op(struct benchmark *bench, struct operation_info *info) { get_item(bench, info); return obj_bench.args->queue ? queue_remove_op(info) : obj_remove_op(info); } /* * obj_remove_free_op -- main operation of the obj_remove_free benchmark. */ static int obj_remove_free_op(struct benchmark *bench, struct operation_info *info) { get_item(bench, info); struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; POBJ_LIST_REMOVE_FREE(obj_bench.pop, &obj_worker->head, obj_worker->elm.itemp, field); return 0; } /* * obj_move_op -- main operation of the obj_move benchmark. */ static int obj_move_op(struct benchmark *bench, struct operation_info *info) { if (get_move_item(bench, info)) return -1; struct obj_worker *obj_worker = (struct obj_worker *)info->worker->priv; POBJ_LIST_MOVE_ELEMENT_BEFORE(obj_bench.pop, &obj_worker->head, &obj_worker->list_move->head, obj_worker->list_move->elm.itemp, obj_worker->elm.itemp, field, field); return 0; } /* * free_worker -- free common worker state */ static void free_worker(struct obj_worker *obj_worker) { if (obj_bench.position_mode == POSITION_MODE_RAND) free(obj_worker->fn_positions); free(obj_worker); } /* * free_worker_list -- worker de-initialization function for: obj_insert_new, * obj_remove_free, obj_move. Requires releasing objects directly from list. */ static void free_worker_list(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct obj_worker *obj_worker = (struct obj_worker *)worker->priv; obj_bench.args->queue ? queue_free_worker_list(obj_worker) : obj_free_worker_list(obj_worker); free_worker(obj_worker); } /* * obj_free_worker_items -- worker de-initialization function of obj_insert and * obj_remove benchmarks, where deallocation can't be performed directly on the * list and where is possibility of using queue flag. */ static void free_worker_items(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct obj_worker *obj_worker = (struct obj_worker *)worker->priv; struct obj_list_args *obj_args = (struct obj_list_args *)args->opts; obj_args->queue ? queue_free_worker_items(obj_worker) : obj_free_worker_items(obj_worker); free_worker(obj_worker); } /* * obj_move_free_worker -- special part for the worker de-initialization * function of obj_move benchmarks. */ static void obj_move_free_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct obj_worker *obj_worker = (struct obj_worker *)worker->priv; while (!POBJ_LIST_EMPTY(&obj_worker->list_move->head)) POBJ_LIST_REMOVE_FREE( obj_bench.pop, &obj_worker->list_move->head, POBJ_LIST_LAST(&obj_worker->list_move->head, field), field); if (obj_bench.position_mode == POSITION_MODE_RAND) free(obj_worker->list_move->fn_positions); free(obj_worker->list_move); free_worker_list(bench, args, worker); } /* * obj_init_worker -- common part for the worker initialization for: * obj_insert, obj_insert_new, obj_remove obj_remove_free and obj_move. */ static int obj_init_worker(struct worker_info *worker, size_t n_elm, size_t list_len) { struct obj_worker *obj_worker = (struct obj_worker *)calloc(1, sizeof(struct obj_worker)); if (obj_worker == NULL) { perror("calloc"); return -1; } worker->priv = obj_worker; obj_worker->n_elm = obj_bench.max_len; obj_worker->list_move = NULL; if (obj_bench.position_mode == POSITION_MODE_RAND) { obj_worker->fn_positions = random_positions(); if (obj_worker->fn_positions == NULL) goto err; } if (obj_bench.fn_init(worker, n_elm, list_len) != 0) goto err_positions; return 0; err_positions: free(obj_worker->fn_positions); err: free(obj_worker); return -1; } /* * obj_insert_init_worker -- worker initialization functions of the obj_insert * benchmark. */ static int obj_insert_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { return obj_init_worker(worker, obj_bench.max_len, obj_bench.min_len); } /* * obj_insert_new_init_worker -- worker initialization functions of the * obj_insert_new benchmark. */ static int obj_insert_new_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { return obj_init_worker(worker, obj_bench.min_len, obj_bench.min_len); } /* * obj_remove_init_worker -- worker initialization functions of the obj_remove * and obj_remove_free benchmarks. */ static int obj_remove_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { return obj_init_worker(worker, obj_bench.max_len, obj_bench.max_len); } /* * obj_move_init_worker -- worker initialization functions of the obj_move * benchmark. */ static int obj_move_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { if (obj_init_worker(worker, obj_bench.max_len, obj_bench.max_len) != 0) return -1; struct obj_worker *obj_worker = (struct obj_worker *)worker->priv; obj_worker->list_move = (struct obj_worker *)calloc(1, sizeof(struct obj_worker)); if (obj_worker->list_move == NULL) { perror("calloc"); goto free; } size_t i; if (obj_bench.position_mode == POSITION_MODE_RAND) { obj_worker->list_move->fn_positions = random_positions(); if (obj_worker->list_move->fn_positions == NULL) goto free_list_move; } for (i = 0; i < obj_bench.min_len; i++) { size_t size = obj_bench.alloc_sizes[i]; POBJ_LIST_INSERT_NEW_TAIL(obj_bench.pop, &obj_worker->list_move->head, field, size, NULL, NULL); if (TOID_IS_NULL(POBJ_LIST_LAST(&obj_worker->list_move->head, field))) { perror("pmemobj_list_insert_new"); goto free_all; } } return 0; free_all: for (; i > 0; i--) { POBJ_LIST_REMOVE_FREE( obj_bench.pop, &obj_worker->list_move->head, POBJ_LIST_LAST(&obj_worker->list_move->head, field), field); } free(obj_worker->list_move->fn_positions); free_list_move: free(obj_worker->list_move); free: free_worker_list(bench, args, worker); return -1; } /* * obj_init - common part of the benchmark initialization for: obj_insert, * obj_insert_new, obj_remove, obj_remove_free and obj_move used in their init * functions. Parses command line arguments, sets variables and * creates persistent pool. */ static int obj_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); obj_bench.args = (struct obj_list_args *)args->opts; obj_bench.min_len = obj_bench.args->list_len + 1; obj_bench.max_len = args->n_ops_per_thread + obj_bench.min_len; obj_bench.fn_init = obj_bench.args->queue ? queue_init_list : obj_init_list; /* Decide if use random or state allocation sizes */ size_t obj_size = args->dsize < sizeof(struct item) ? sizeof(struct item) : args->dsize; size_t min_size = obj_bench.args->min_size < sizeof(struct item) ? sizeof(struct item) : obj_bench.args->min_size; obj_bench.alloc_sizes = random_values( min_size, obj_size, obj_bench.max_len, sizeof(struct item)); if (obj_bench.alloc_sizes == NULL) goto free_random_types; /* Decide where operations will be performed */ obj_bench.position_mode = parse_args(obj_bench.args->position, POSITION_MODE_UNKNOWN, position_names); if (obj_bench.position_mode == POSITION_MODE_UNKNOWN) goto free_all; obj_bench.fn_position = positions[obj_bench.position_mode]; if (!obj_bench.args->queue) { /* Decide what type number will be used */ obj_bench.type_mode = parse_args(obj_bench.args->type_num, TYPE_MODE_UNKNOWN, type_num_names); if (obj_bench.type_mode == TYPE_MODE_UNKNOWN) return -1; obj_bench.fn_type_num = type_num_modes[obj_bench.type_mode]; if (obj_bench.type_mode == TYPE_MODE_RAND) { obj_bench.random_types = random_values( 1, UINT32_MAX, obj_bench.max_len, 0); if (obj_bench.random_types == NULL) return -1; } /* * Multiplication by FACTOR prevents from out of memory error * as the actual size of the allocated persistent objects * is always larger than requested. */ size_t psize = (args->n_ops_per_thread + obj_bench.min_len + 1) * obj_size * args->n_threads * FACTOR; if (args->is_poolset) { if (args->fsize < psize) { fprintf(stderr, "insufficient size " "of poolset\n"); goto free_all; } psize = 0; } else { if (psize < PMEMOBJ_MIN_POOL) psize = PMEMOBJ_MIN_POOL; } /* Create pmemobj pool. */ if ((obj_bench.pop = pmemobj_create(args->fname, LAYOUT_NAME, psize, args->fmode)) == NULL) { perror(pmemobj_errormsg()); goto free_all; } } return 0; free_all: free(obj_bench.alloc_sizes); free_random_types: if (obj_bench.type_mode == TYPE_MODE_RAND) free(obj_bench.random_types); return -1; } /* * obj_exit -- common part for the exit function for: obj_insert, * obj_insert_new, obj_remove, obj_remove_free and obj_move used in their exit * functions. */ static int obj_exit(struct benchmark *bench, struct benchmark_args *args) { if (!obj_bench.args->queue) { pmemobj_close(obj_bench.pop); if (obj_bench.type_mode == TYPE_MODE_RAND) free(obj_bench.random_types); } free(obj_bench.alloc_sizes); return 0; } /* obj_list_clo -- array defining common command line arguments. */ static struct benchmark_clo obj_list_clo[6]; static struct benchmark_info obj_insert; static struct benchmark_info obj_remove; static struct benchmark_info obj_insert_new; static struct benchmark_info obj_remove_free; static struct benchmark_info obj_move; CONSTRUCTOR(pmem_atomic_list_costructor) void pmem_atomic_list_costructor(void) { obj_list_clo[0].opt_short = 'T'; obj_list_clo[0].opt_long = "type-number"; obj_list_clo[0].descr = "Type number mode - one, per-thread, " "rand"; obj_list_clo[0].def = "one"; obj_list_clo[0].off = clo_field_offset(struct obj_list_args, type_num); obj_list_clo[0].type = CLO_TYPE_STR; obj_list_clo[1].opt_short = 'P'; obj_list_clo[1].opt_long = "position"; obj_list_clo[1].descr = "Place where operation will be " "performed - head, tail, rand, middle"; obj_list_clo[1].def = "middle"; obj_list_clo[1].off = clo_field_offset(struct obj_list_args, position); obj_list_clo[1].type = CLO_TYPE_STR; obj_list_clo[2].opt_short = 'l'; obj_list_clo[2].opt_long = "list-len"; obj_list_clo[2].type = CLO_TYPE_UINT; obj_list_clo[2].descr = "Initial list len"; obj_list_clo[2].off = clo_field_offset(struct obj_list_args, list_len); obj_list_clo[2].def = "1"; obj_list_clo[2].type_uint.size = clo_field_size(struct obj_list_args, list_len); obj_list_clo[2].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; obj_list_clo[2].type_uint.min = 1; obj_list_clo[2].type_uint.max = ULONG_MAX; obj_list_clo[3].opt_short = 'm'; obj_list_clo[3].opt_long = "min-size"; obj_list_clo[3].type = CLO_TYPE_UINT; obj_list_clo[3].descr = "Min allocation size"; obj_list_clo[3].off = clo_field_offset(struct obj_list_args, min_size); obj_list_clo[3].def = "0"; obj_list_clo[3].type_uint.size = clo_field_size(struct obj_list_args, min_size); obj_list_clo[3].type_uint.base = CLO_INT_BASE_DEC; obj_list_clo[3].type_uint.min = 0; obj_list_clo[3].type_uint.max = UINT_MAX; obj_list_clo[4].opt_short = 's'; obj_list_clo[4].type_uint.max = INT_MAX; obj_list_clo[4].opt_long = "seed"; obj_list_clo[4].type = CLO_TYPE_UINT; obj_list_clo[4].descr = "Seed value"; obj_list_clo[4].off = clo_field_offset(struct obj_list_args, seed); obj_list_clo[4].def = "0"; obj_list_clo[4].type_uint.size = clo_field_size(struct obj_list_args, seed); obj_list_clo[4].type_uint.base = CLO_INT_BASE_DEC; obj_list_clo[4].type_uint.min = 0; /* * nclos field in benchmark_info structures is decremented to make * queue option available only for obj_isert, obj_remove */ obj_list_clo[5].opt_short = 'q'; obj_list_clo[5].opt_long = "queue"; obj_list_clo[5].descr = "Use circleq from queue.h instead " "pmemobj"; obj_list_clo[5].type = CLO_TYPE_FLAG; obj_list_clo[5].off = clo_field_offset(struct obj_list_args, queue); obj_insert.name = "obj_insert"; obj_insert.brief = "pmemobj_list_insert() benchmark"; obj_insert.init = obj_init; obj_insert.exit = obj_exit; obj_insert.multithread = true; obj_insert.multiops = true; obj_insert.init_worker = obj_insert_init_worker; obj_insert.free_worker = free_worker_items; obj_insert.operation = insert_op; obj_insert.measure_time = true; obj_insert.clos = obj_list_clo; obj_insert.nclos = ARRAY_SIZE(obj_list_clo); obj_insert.opts_size = sizeof(struct obj_list_args); obj_insert.rm_file = true; obj_insert.allow_poolset = true; REGISTER_BENCHMARK(obj_insert); obj_remove.name = "obj_remove"; obj_remove.brief = "pmemobj_list_remove() benchmark " "without freeing element"; obj_remove.init = obj_init; obj_remove.exit = obj_exit; obj_remove.multithread = true; obj_remove.multiops = true; obj_remove.init_worker = obj_remove_init_worker; obj_remove.free_worker = free_worker_items; obj_remove.operation = remove_op; obj_remove.measure_time = true; obj_remove.clos = obj_list_clo; obj_remove.nclos = ARRAY_SIZE(obj_list_clo); obj_remove.opts_size = sizeof(struct obj_list_args); obj_remove.rm_file = true; obj_remove.allow_poolset = true; REGISTER_BENCHMARK(obj_remove); obj_insert_new.name = "obj_insert_new"; obj_insert_new.brief = "pmemobj_list_insert_new() benchmark"; obj_insert_new.init = obj_init; obj_insert_new.exit = obj_exit; obj_insert_new.multithread = true; obj_insert_new.multiops = true; obj_insert_new.init_worker = obj_insert_new_init_worker; obj_insert_new.free_worker = free_worker_list; obj_insert_new.operation = obj_insert_new_op; obj_insert_new.measure_time = true; obj_insert_new.clos = obj_list_clo; obj_insert_new.nclos = ARRAY_SIZE(obj_list_clo) - 1; obj_insert_new.opts_size = sizeof(struct obj_list_args); obj_insert_new.rm_file = true; obj_insert_new.allow_poolset = true; REGISTER_BENCHMARK(obj_insert_new); obj_remove_free.name = "obj_remove_free"; obj_remove_free.brief = "pmemobj_list_remove() benchmark " "with freeing element"; obj_remove_free.init = obj_init; obj_remove_free.exit = obj_exit; obj_remove_free.multithread = true; obj_remove_free.multiops = true; obj_remove_free.init_worker = obj_remove_init_worker; obj_remove_free.free_worker = free_worker_list; obj_remove_free.operation = obj_remove_free_op; obj_remove_free.measure_time = true; obj_remove_free.clos = obj_list_clo; obj_remove_free.nclos = ARRAY_SIZE(obj_list_clo) - 1; obj_remove_free.opts_size = sizeof(struct obj_list_args); obj_remove_free.rm_file = true; obj_remove_free.allow_poolset = true; REGISTER_BENCHMARK(obj_remove_free); obj_move.name = "obj_move"; obj_move.brief = "pmemobj_list_move() benchmark"; obj_move.init = obj_init; obj_move.exit = obj_exit; obj_move.multithread = true; obj_move.multiops = true; obj_move.init_worker = obj_move_init_worker; obj_move.free_worker = obj_move_free_worker; obj_move.operation = obj_move_op; obj_move.measure_time = true; obj_move.clos = obj_list_clo; obj_move.nclos = ARRAY_SIZE(obj_list_clo) - 1; obj_move.opts_size = sizeof(struct obj_list_args); obj_move.rm_file = true; obj_move.allow_poolset = true; REGISTER_BENCHMARK(obj_move); } pmdk-1.4.1/src/benchmarks/pmemobj_gen.cpp000066400000000000000000000456111331545616200203570ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmemobj_gen.cpp -- benchmark for pmemobj_direct() * and pmemobj_open() functions. */ #include #include #include #include #include #include #include #include #include #include "benchmark.hpp" #include "libpmemobj.h" #define LAYOUT_NAME "benchmark" #define FACTOR 4 #define DIR_MODE 0700 #define FILE_MODE 0666 #define PART_NAME "/part" #define MAX_DIGITS 2 struct pobj_bench; struct pobj_worker; typedef size_t (*fn_type_num_t)(struct pobj_bench *ob, size_t worker_idx, size_t op_idx); typedef size_t (*fn_size_t)(struct pobj_bench *ob, size_t idx); typedef size_t (*fn_num_t)(size_t idx); /* * Enumeration used to determine the mode of the assigning type_number * value to the persistent objects. */ enum type_mode { TYPE_MODE_ONE, TYPE_MODE_PER_THREAD, TYPE_MODE_RAND, MAX_TYPE_MODE, }; /* * pobj_args - Stores command line parsed arguments. * * rand_type : Use random type number for every new allocated object. * Default, there is one type number for all objects. * * range : Use random allocation size. * * min_size : Minimum allocation size. * * n_objs : Number of objects allocated per thread * * one_pool : Use one common pool for all thread * * one_obj : Create and use one object per thread * * obj_size : Size of each allocated object * * n_ops : Number of operations */ struct pobj_args { char *type_num; bool range; unsigned min_size; size_t n_objs; bool one_pool; bool one_obj; size_t obj_size; size_t n_ops; }; /* * pobj_bench - Stores variables used in benchmark, passed within functions. * * pop : Pointer to the persistent pool. * * pa : Stores pobj_args structure. * * sets : Stores files names using to create pool per thread * * random_types : Random type numbers for persistent objects. * * rand_sizes : random values with allocation sizes. * * n_pools : Number of created pools. * * n_objs : Number of object created per thread. * * type_mode : Type_mode enum value * * fn_type_num : Function returning proper type number for each object. * * fn_size : Function returning proper size of allocation. * * pool : Functions returning number of thread if * one pool per thread created or index 0 if not. * * obj : Function returning number of operation if flag set * to false or index 0 if set to true. */ struct pobj_bench { PMEMobjpool **pop; struct pobj_args *args_priv; const char **sets; size_t *random_types; size_t *rand_sizes; size_t n_pools; int type_mode; fn_type_num_t fn_type_num; fn_size_t fn_size; fn_num_t pool; fn_num_t obj; }; /* * pobj_worker - Stores variables used by one thread. */ struct pobj_worker { PMEMoid *oids; }; /* * type_mode_one -- always returns 0, as in the mode TYPE_MODE_ONE * all of the persistent objects have the same type_number value. */ static size_t type_mode_one(struct pobj_bench *bench_priv, size_t worker_idx, size_t op_idx) { return 0; } /* * type_mode_per_thread -- always returns worker index, as in the mode * TYPE_MODE_PER_THREAD all persistent object allocated by the same thread * have the same type_number value. */ static size_t type_mode_per_thread(struct pobj_bench *bench_priv, size_t worker_idx, size_t op_idx) { return worker_idx; } /* * type_mode_rand -- returns the value from the random_types array assigned * for the specific operation in a specific thread. */ static size_t type_mode_rand(struct pobj_bench *bench_priv, size_t worker_idx, size_t op_idx) { return bench_priv->random_types[op_idx]; } /* * range_size -- returns size of object allocation from rand_sizes array. */ static size_t range_size(struct pobj_bench *bench_priv, size_t idx) { return bench_priv->rand_sizes[idx]; } /* * static_size -- returns always the same size of object allocation. */ static size_t static_size(struct pobj_bench *bench_priv, size_t idx) { return bench_priv->args_priv->obj_size; } /* * diff_num -- returns given index */ static size_t diff_num(size_t idx) { return idx; } /* * one_num -- returns always the same index. */ static size_t one_num(size_t idx) { return 0; } static fn_type_num_t type_mode_func[MAX_TYPE_MODE] = { type_mode_one, type_mode_per_thread, type_mode_rand}; const char *type_mode_names[MAX_TYPE_MODE] = {"one", "per-thread", "rand"}; /* * parse_type_mode -- parses command line "--type-number" argument * and returns proper type_mode enum value. */ static enum type_mode parse_type_mode(const char *arg) { enum type_mode i = TYPE_MODE_ONE; for (; i < MAX_TYPE_MODE && strcmp(arg, type_mode_names[i]) != 0; i = (enum type_mode)(i + 1)) ; return i; } /* * rand_sizes -- allocates array and calculates random values as allocation * sizes for each object. Used only when range flag set. */ static size_t * rand_sizes(size_t min, size_t max, size_t n_ops) { assert(n_ops != 0); size_t *rand_sizes = (size_t *)malloc(n_ops * sizeof(size_t)); if (rand_sizes == NULL) { perror("malloc"); return NULL; } for (size_t i = 0; i < n_ops; i++) { rand_sizes[i] = RRAND(max, min); } return rand_sizes; } /* * random_types -- allocates array and calculates random values to assign * type_number for each object. */ static int random_types(struct pobj_bench *bench_priv, struct benchmark_args *args) { assert(bench_priv->args_priv->n_objs != 0); bench_priv->random_types = (size_t *)malloc( bench_priv->args_priv->n_objs * sizeof(size_t)); if (bench_priv->random_types == NULL) { perror("malloc"); return -1; } for (size_t i = 0; i < bench_priv->args_priv->n_objs; i++) bench_priv->random_types[i] = rand() % UINT32_MAX; return 0; } /* * pobj_init - common part of the benchmark initialization functions. * Parses command line arguments, set variables and creates persistent pools. */ static int pobj_init(struct benchmark *bench, struct benchmark_args *args) { unsigned i = 0; size_t psize; size_t n_objs; assert(bench != NULL); assert(args != NULL); struct pobj_bench *bench_priv = (struct pobj_bench *)malloc(sizeof(struct pobj_bench)); if (bench_priv == NULL) { perror("malloc"); return -1; } assert(args->opts != NULL); bench_priv->args_priv = (struct pobj_args *)args->opts; bench_priv->args_priv->obj_size = args->dsize; bench_priv->args_priv->range = bench_priv->args_priv->min_size > 0 ? true : false; bench_priv->n_pools = !bench_priv->args_priv->one_pool ? args->n_threads : 1; bench_priv->pool = bench_priv->n_pools > 1 ? diff_num : one_num; bench_priv->obj = !bench_priv->args_priv->one_obj ? diff_num : one_num; if (args->is_poolset && bench_priv->n_pools > 1) { fprintf(stderr, "cannot use poolset for multiple pools," " please use -P|--one-pool option instead"); goto free_bench_priv; } /* * Multiplication by FACTOR prevents from out of memory error * as the actual size of the allocated persistent objects * is always larger than requested. */ n_objs = bench_priv->args_priv->n_objs; if (bench_priv->n_pools == 1) n_objs *= args->n_threads; psize = n_objs * args->dsize * args->n_threads * FACTOR; if (psize < PMEMOBJ_MIN_POOL) psize = PMEMOBJ_MIN_POOL; /* assign type_number determining function */ bench_priv->type_mode = parse_type_mode(bench_priv->args_priv->type_num); switch (bench_priv->type_mode) { case MAX_TYPE_MODE: fprintf(stderr, "unknown type mode"); goto free_bench_priv; case TYPE_MODE_RAND: if (random_types(bench_priv, args)) goto free_bench_priv; break; default: bench_priv->random_types = NULL; } bench_priv->fn_type_num = type_mode_func[bench_priv->type_mode]; /* assign size determining function */ bench_priv->fn_size = bench_priv->args_priv->range ? range_size : static_size; bench_priv->rand_sizes = NULL; if (bench_priv->args_priv->range) { if (bench_priv->args_priv->min_size > args->dsize) { fprintf(stderr, "Invalid allocation size"); goto free_random_types; } bench_priv->rand_sizes = rand_sizes(bench_priv->args_priv->min_size, bench_priv->args_priv->obj_size, bench_priv->args_priv->n_objs); if (bench_priv->rand_sizes == NULL) goto free_random_types; } assert(bench_priv->n_pools > 0); bench_priv->pop = (PMEMobjpool **)calloc(bench_priv->n_pools, sizeof(PMEMobjpool *)); if (bench_priv->pop == NULL) { perror("calloc"); goto free_random_sizes; } bench_priv->sets = (const char **)calloc(bench_priv->n_pools, sizeof(const char *)); if (bench_priv->sets == NULL) { perror("calloc"); goto free_pop; } if (bench_priv->n_pools > 1) { assert(!args->is_poolset); if (util_file_mkdir(args->fname, DIR_MODE) != 0) { fprintf(stderr, "cannot create directory\n"); goto free_sets; } size_t path_len = (strlen(PART_NAME) + strlen(args->fname)) + MAX_DIGITS + 1; for (i = 0; i < bench_priv->n_pools; i++) { bench_priv->sets[i] = (char *)malloc(path_len * sizeof(char)); if (bench_priv->sets[i] == NULL) { perror("malloc"); goto free_sets; } int ret = snprintf((char *)bench_priv->sets[i], path_len, "%s%s%02x", args->fname, PART_NAME, i); if (ret < 0 || ret >= (int)path_len) { perror("snprintf"); goto free_sets; } bench_priv->pop[i] = pmemobj_create(bench_priv->sets[i], LAYOUT_NAME, psize, FILE_MODE); if (bench_priv->pop[i] == NULL) { perror(pmemobj_errormsg()); goto free_sets; } } } else { if (args->is_poolset) { if (args->fsize < psize) { fprintf(stderr, "insufficient size of " "poolset\n"); goto free_pools; } psize = 0; } bench_priv->sets[0] = (const char *)args->fname; bench_priv->pop[0] = pmemobj_create( bench_priv->sets[0], LAYOUT_NAME, psize, FILE_MODE); if (bench_priv->pop[0] == NULL) { perror(pmemobj_errormsg()); goto free_pools; } } pmembench_set_priv(bench, bench_priv); return 0; free_sets: for (; i > 0; i--) { pmemobj_close(bench_priv->pop[i - 1]); free((char *)bench_priv->sets[i - 1]); } free_pools: free(bench_priv->sets); free_pop: free(bench_priv->pop); free_random_sizes: free(bench_priv->rand_sizes); free_random_types: free(bench_priv->random_types); free_bench_priv: free(bench_priv); return -1; } /* * pobj_direct_init -- special part of pobj_direct benchmark initialization. */ static int pobj_direct_init(struct benchmark *bench, struct benchmark_args *args) { struct pobj_args *pa = (struct pobj_args *)args->opts; pa->n_objs = pa->one_obj ? 1 : args->n_ops_per_thread; if (pobj_init(bench, args) != 0) return -1; return 0; } /* * pobj_exit -- common part for the benchmarks exit functions */ static int pobj_exit(struct benchmark *bench, struct benchmark_args *args) { size_t i; struct pobj_bench *bench_priv = (struct pobj_bench *)pmembench_get_priv(bench); if (bench_priv->n_pools > 1) { for (i = 0; i < bench_priv->n_pools; i++) { pmemobj_close(bench_priv->pop[i]); free((char *)bench_priv->sets[i]); } } else { pmemobj_close(bench_priv->pop[0]); } free(bench_priv->sets); free(bench_priv->pop); free(bench_priv->rand_sizes); free(bench_priv->random_types); free(bench_priv); return 0; } /* * pobj_init_worker -- worker initialization */ static int pobj_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { size_t i, idx = worker->index; struct pobj_bench *bench_priv = (struct pobj_bench *)pmembench_get_priv(bench); struct pobj_worker *pw = (struct pobj_worker *)calloc(1, sizeof(struct pobj_worker)); if (pw == NULL) { perror("calloc"); return -1; } worker->priv = pw; pw->oids = (PMEMoid *)calloc(bench_priv->args_priv->n_objs, sizeof(PMEMoid)); if (pw->oids == NULL) { free(pw); perror("calloc"); return -1; } PMEMobjpool *pop = bench_priv->pop[bench_priv->pool(idx)]; for (i = 0; i < bench_priv->args_priv->n_objs; i++) { size_t size = bench_priv->fn_size(bench_priv, i); size_t type = bench_priv->fn_type_num(bench_priv, idx, i); if (pmemobj_alloc(pop, &pw->oids[i], size, type, NULL, NULL) != 0) { perror("pmemobj_alloc"); goto out; } } return 0; out: for (; i > 0; i--) pmemobj_free(&pw->oids[i - 1]); free(pw->oids); free(pw); return -1; } /* * pobj_direct_op -- main operations of the obj_direct benchmark. */ static int pobj_direct_op(struct benchmark *bench, struct operation_info *info) { struct pobj_bench *bench_priv = (struct pobj_bench *)pmembench_get_priv(bench); struct pobj_worker *pw = (struct pobj_worker *)info->worker->priv; size_t idx = bench_priv->obj(info->index); if (pmemobj_direct(pw->oids[idx]) == NULL) return -1; return 0; } /* * pobj_open_op -- main operations of the obj_open benchmark. */ static int pobj_open_op(struct benchmark *bench, struct operation_info *info) { struct pobj_bench *bench_priv = (struct pobj_bench *)pmembench_get_priv(bench); size_t idx = bench_priv->pool(info->worker->index); pmemobj_close(bench_priv->pop[idx]); bench_priv->pop[idx] = pmemobj_open(bench_priv->sets[idx], LAYOUT_NAME); if (bench_priv->pop[idx] == NULL) return -1; return 0; } /* * pobj_free_worker -- worker exit function */ static void pobj_free_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct pobj_worker *pw = (struct pobj_worker *)worker->priv; struct pobj_bench *bench_priv = (struct pobj_bench *)pmembench_get_priv(bench); for (size_t i = 0; i < bench_priv->args_priv->n_objs; i++) pmemobj_free(&pw->oids[i]); free(pw->oids); free(pw); } static struct benchmark_info obj_open; static struct benchmark_info obj_direct; /* Array defining common command line arguments. */ static struct benchmark_clo pobj_direct_clo[4]; static struct benchmark_clo pobj_open_clo[3]; CONSTRUCTOR(pmemobj_gen_costructor) void pmemobj_gen_costructor(void) { pobj_direct_clo[0].opt_short = 'T'; pobj_direct_clo[0].opt_long = "type-number"; pobj_direct_clo[0].descr = "Type number mode - one, per-thread, " "rand"; pobj_direct_clo[0].def = "one"; pobj_direct_clo[0].off = clo_field_offset(struct pobj_args, type_num); pobj_direct_clo[0].type = CLO_TYPE_STR; pobj_direct_clo[1].opt_short = 'm'; pobj_direct_clo[1].opt_long = "min-size"; pobj_direct_clo[1].type = CLO_TYPE_UINT; pobj_direct_clo[1].descr = "Minimum allocation size"; pobj_direct_clo[1].off = clo_field_offset(struct pobj_args, min_size); pobj_direct_clo[1].def = "0"; pobj_direct_clo[1].type_uint.size = clo_field_size(struct pobj_args, min_size); pobj_direct_clo[1].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; pobj_direct_clo[1].type_uint.min = 0; pobj_direct_clo[1].type_uint.max = UINT_MAX; pobj_direct_clo[2].opt_short = 'P'; pobj_direct_clo[2].opt_long = "one-pool"; pobj_direct_clo[2].descr = "Create one pool for all threads"; pobj_direct_clo[2].type = CLO_TYPE_FLAG; pobj_direct_clo[2].off = clo_field_offset(struct pobj_args, one_pool); pobj_direct_clo[3].opt_short = 'O'; pobj_direct_clo[3].opt_long = "one-object"; pobj_direct_clo[3].descr = "Use only one object per thread"; pobj_direct_clo[3].type = CLO_TYPE_FLAG; pobj_direct_clo[3].off = clo_field_offset(struct pobj_args, one_obj); pobj_open_clo[0].opt_short = 'T', pobj_open_clo[0].opt_long = "type-number", pobj_open_clo[0].descr = "Type number mode - one, " "per-thread, rand", pobj_open_clo[0].def = "one", pobj_open_clo[0].off = clo_field_offset(struct pobj_args, type_num), pobj_open_clo[0].type = CLO_TYPE_STR, pobj_open_clo[1].opt_short = 'm', pobj_open_clo[1].opt_long = "min-size", pobj_open_clo[1].type = CLO_TYPE_UINT, pobj_open_clo[1].descr = "Minimum allocation size", pobj_open_clo[1].off = clo_field_offset(struct pobj_args, min_size), pobj_open_clo[1].def = "0", pobj_open_clo[1].type_uint.size = clo_field_size(struct pobj_args, min_size), pobj_open_clo[1].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX, pobj_open_clo[1].type_uint.min = 0, pobj_open_clo[1].type_uint.max = UINT_MAX, pobj_open_clo[2].opt_short = 'o'; pobj_open_clo[2].opt_long = "objects"; pobj_open_clo[2].type = CLO_TYPE_UINT; pobj_open_clo[2].descr = "Number of objects in each pool"; pobj_open_clo[2].off = clo_field_offset(struct pobj_args, n_objs); pobj_open_clo[2].def = "1"; pobj_open_clo[2].type_uint.size = clo_field_size(struct pobj_args, n_objs); pobj_open_clo[2].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; pobj_open_clo[2].type_uint.min = 1; pobj_open_clo[2].type_uint.max = UINT_MAX; obj_open.name = "obj_open"; obj_open.brief = "pmemobj_open() benchmark"; obj_open.init = pobj_init; obj_open.exit = pobj_exit; obj_open.multithread = true; obj_open.multiops = true; obj_open.init_worker = pobj_init_worker; obj_open.free_worker = pobj_free_worker; obj_open.operation = pobj_open_op; obj_open.measure_time = true; obj_open.clos = pobj_open_clo; obj_open.nclos = ARRAY_SIZE(pobj_open_clo); obj_open.opts_size = sizeof(struct pobj_args); obj_open.rm_file = true; obj_open.allow_poolset = true; REGISTER_BENCHMARK(obj_open); obj_direct.name = "obj_direct"; obj_direct.brief = "pmemobj_direct() benchmark"; obj_direct.init = pobj_direct_init; obj_direct.exit = pobj_exit; obj_direct.multithread = true; obj_direct.multiops = true; obj_direct.init_worker = pobj_init_worker; obj_direct.free_worker = pobj_free_worker; obj_direct.operation = pobj_direct_op; obj_direct.measure_time = true; obj_direct.clos = pobj_direct_clo; obj_direct.nclos = ARRAY_SIZE(pobj_direct_clo); obj_direct.opts_size = sizeof(struct pobj_args); obj_direct.rm_file = true; obj_direct.allow_poolset = true; REGISTER_BENCHMARK(obj_direct); }; pmdk-1.4.1/src/benchmarks/pmemobj_persist.cpp000066400000000000000000000166711331545616200213030ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmemobj_persist.cpp -- pmemobj persist benchmarks definition */ #include #include #include #include #include #include #include #include #include #include #include "benchmark.hpp" #include "libpmemobj.h" #include "util.h" /* * The factor used for PMEM pool size calculation, accounts for metadata, * fragmentation and etc. */ #define FACTOR 3 /* The minimum allocation size that pmalloc can perform */ #define ALLOC_MIN_SIZE 64 /* OOB and allocation header size */ #define OOB_HEADER_SIZE 64 #define CONST_B 0xFF /* * prog_args -- benchmark specific command line options */ struct prog_args { size_t minsize; /* minimum size for random allocation size */ bool use_random_size; /* if set, use random size allocations */ bool no_warmup; /* do not do warmup */ unsigned seed; /* seed for random numbers */ }; /* * obj_bench -- benchmark context */ struct obj_bench { PMEMobjpool *pop; /* persistent pool handle */ struct prog_args *pa; /* prog_args structure */ PMEMoid *oids; /* vector of allocated objects */ void **ptrs; /* pointers to allocated objects */ uint64_t nobjs; /* number of allocated objects */ size_t obj_size; /* size of each allocated objects */ int const_b; /* memset() value */ }; /* * init_objects -- allocate persistent objects and obtain direct pointers */ static int init_objects(struct obj_bench *ob) { assert(ob->nobjs != 0); ob->oids = (PMEMoid *)malloc(ob->nobjs * sizeof(*ob->oids)); if (!ob->oids) { perror("malloc"); return -1; } ob->ptrs = (void **)malloc(ob->nobjs * sizeof(*ob->ptrs)); if (!ob->ptrs) { perror("malloc"); goto err_malloc; } for (uint64_t i = 0; i < ob->nobjs; i++) { PMEMoid oid; void *ptr; if (pmemobj_alloc(ob->pop, &oid, ob->obj_size, 0, NULL, NULL)) { perror("pmemobj_alloc"); goto err_palloc; } ptr = pmemobj_direct(oid); if (!ptr) { perror("pmemobj_direct"); goto err_palloc; } ob->oids[i] = oid; ob->ptrs[i] = ptr; } return 0; err_palloc: free(ob->ptrs); err_malloc: free(ob->oids); return -1; } /* * do_warmup -- does the warmup by writing the whole pool area */ static void do_warmup(struct obj_bench *ob) { for (uint64_t i = 0; i < ob->nobjs; ++i) { memset(ob->ptrs[i], 0, ob->obj_size); pmemobj_persist(ob->pop, ob->ptrs[i], ob->obj_size); } } /* * obj_persist_op -- actual benchmark operation */ static int obj_persist_op(struct benchmark *bench, struct operation_info *info) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); uint64_t idx = info->worker->index * info->args->n_ops_per_thread + info->index; assert(idx < ob->nobjs); void *ptr = ob->ptrs[idx]; memset(ptr, ob->const_b, ob->obj_size); pmemobj_persist(ob->pop, ptr, ob->obj_size); return 0; } /* * obj_persist_init -- initialization function */ static int obj_persist_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); struct prog_args *pa = (struct prog_args *)args->opts; size_t poolsize; if (pa->minsize >= args->dsize) { fprintf(stderr, "Wrong params - allocation size\n"); return -1; } struct obj_bench *ob = (struct obj_bench *)malloc(sizeof(struct obj_bench)); if (ob == NULL) { perror("malloc"); return -1; } pmembench_set_priv(bench, ob); ob->pa = pa; /* initialize memset() value */ ob->const_b = CONST_B; ob->nobjs = args->n_ops_per_thread * args->n_threads; /* Create pmemobj pool. */ ob->obj_size = args->dsize; if (ob->obj_size < ALLOC_MIN_SIZE) ob->obj_size = ALLOC_MIN_SIZE; /* For data objects */ poolsize = ob->nobjs * (ob->obj_size + OOB_HEADER_SIZE); /* multiply by FACTOR for metadata, fragmentation, etc. */ poolsize = poolsize * FACTOR; if (args->is_poolset) { if (args->fsize < poolsize) { fprintf(stderr, "insufficient size of poolset\n"); goto free_ob; } poolsize = 0; } else { if (poolsize < PMEMOBJ_MIN_POOL) poolsize = PMEMOBJ_MIN_POOL; } poolsize = PAGE_ALIGNED_UP_SIZE(poolsize); ob->pop = pmemobj_create(args->fname, NULL, poolsize, args->fmode); if (ob->pop == NULL) { fprintf(stderr, "%s\n", pmemobj_errormsg()); goto free_ob; } if (init_objects(ob)) { goto free_pop; } if (!ob->pa->no_warmup) { do_warmup(ob); } return 0; free_pop: pmemobj_close(ob->pop); free_ob: free(ob); return -1; } /* * obj_persist_exit -- benchmark cleanup function */ static int obj_persist_exit(struct benchmark *bench, struct benchmark_args *args) { struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench); for (uint64_t i = 0; i < ob->nobjs; ++i) { pmemobj_free(&ob->oids[i]); } pmemobj_close(ob->pop); free(ob->oids); free(ob->ptrs); free(ob); return 0; } static struct benchmark_clo obj_persist_clo[1]; /* Stores information about benchmark. */ static struct benchmark_info obj_persist_info; CONSTRUCTOR(pmemobj_persist_costructor) void pmemobj_persist_costructor(void) { obj_persist_clo[0].opt_short = 'w'; obj_persist_clo[0].opt_long = "no-warmup"; obj_persist_clo[0].descr = "Don't do warmup"; obj_persist_clo[0].def = "false"; obj_persist_clo[0].type = CLO_TYPE_FLAG; obj_persist_clo[0].off = clo_field_offset(struct prog_args, no_warmup); obj_persist_info.name = "pmemobj_persist"; obj_persist_info.brief = "Benchmark for pmemobj_persist() " "operation"; obj_persist_info.init = obj_persist_init; obj_persist_info.exit = obj_persist_exit; obj_persist_info.multithread = true; obj_persist_info.multiops = true; obj_persist_info.operation = obj_persist_op; obj_persist_info.measure_time = true; obj_persist_info.clos = obj_persist_clo; obj_persist_info.nclos = ARRAY_SIZE(obj_persist_clo); obj_persist_info.opts_size = sizeof(struct prog_args); obj_persist_info.rm_file = true; obj_persist_info.allow_poolset = true; REGISTER_BENCHMARK(obj_persist_info); }; pmdk-1.4.1/src/benchmarks/pmemobj_tx.cpp000066400000000000000000001057541331545616200202460ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmemobj_tx.cpp -- pmemobj_tx_alloc(), pmemobj_tx_free(), * pmemobj_tx_realloc(), pmemobj_tx_add_range() benchmarks. */ #include #include #include #include #include #include #include #include "benchmark.hpp" #include "libpmemobj.h" #define LAYOUT_NAME "benchmark" #define FACTOR 1.2f #define ALLOC_OVERHEAD 64 /* * operations number is limited to prevent stack overflow during * performing recursive functions. */ #define MAX_OPS 10000 TOID_DECLARE(struct item, 0); struct obj_tx_bench; struct obj_tx_worker; int obj_tx_init(struct benchmark *bench, struct benchmark_args *args); int obj_tx_exit(struct benchmark *bench, struct benchmark_args *args); /* * type_num_mode -- type number mode */ enum type_num_mode { NUM_MODE_ONE, NUM_MODE_PER_THREAD, NUM_MODE_RAND, NUM_MODE_UNKNOWN }; /* * op_mode -- operation type */ enum op_mode { OP_MODE_COMMIT, OP_MODE_ABORT, OP_MODE_ABORT_NESTED, OP_MODE_ONE_OBJ, OP_MODE_ONE_OBJ_NESTED, OP_MODE_ONE_OBJ_RANGE, OP_MODE_ONE_OBJ_NESTED_RANGE, OP_MODE_ALL_OBJ, OP_MODE_ALL_OBJ_NESTED, OP_MODE_UNKNOWN }; /* * lib_mode -- operation type */ enum lib_mode { LIB_MODE_DRAM, LIB_MODE_OBJ_TX, LIB_MODE_OBJ_ATOMIC, LIB_MODE_NONE, }; /* * nesting_mode -- nesting type */ enum nesting_mode { NESTING_MODE_SIM, NESTING_MODE_TX, NESTING_MODE_UNKNOWN, }; /* * add_range_mode -- operation type for obj_add_range benchmark */ enum add_range_mode { ADD_RANGE_MODE_ONE_TX, ADD_RANGE_MODE_NESTED_TX }; /* * parse_mode -- parsing function type */ enum parse_mode { PARSE_OP_MODE, PARSE_OP_MODE_ADD_RANGE }; typedef size_t (*fn_type_num_t)(struct obj_tx_bench *obj_bench, size_t worker_idx, size_t op_idx); typedef size_t (*fn_num_t)(size_t idx); typedef int (*fn_op_t)(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx); typedef struct offset (*fn_os_off_t)(struct obj_tx_bench *obj_bench, size_t idx); typedef enum op_mode (*fn_parse_t)(const char *arg); /* * obj_tx_args -- stores command line parsed arguments. */ struct obj_tx_args { /* * operation which will be performed when flag io set to false. * modes for obj_tx_alloc, obj_tx_free and obj_tx_realloc: * - basic - transaction will be committed * - abort - 'external' transaction will be aborted. * - abort-nested - all nested transactions will be * aborted. * * modes for obj_tx_add_range benchmark: * - basic - one object is added to undo log many times in * one transaction. * - range - fields of one object are added to undo * log many times in one transaction. * - all-obj - all objects are added to undo log in * one transaction. * - range-nested - fields of one object are added to undo * log many times in many nested transactions. * - one-obj-nested - one object is added to undo log many * times in many nested transactions. * - all-obj-nested - all objects are added to undo log in * many separate, nested transactions. */ char *operation; /* * type number for each persistent object. There are three modes: * - one - all of objects have the same type number * - per-thread - all of object allocated by the same * thread have the same type number * - rand - type numbers are assigned randomly for * each persistent object */ char *type_num; /* * define s which library will be used in main operations There are * three modes in which benchmark can be run: * - tx - uses PMEM transactions * - pmem - uses PMEM without transactions * - dram - does not use PMEM */ char *lib; unsigned nested; /* number of nested transactions */ unsigned min_size; /* minimum allocation size */ unsigned min_rsize; /* minimum reallocation size */ unsigned rsize; /* reallocation size */ bool change_type; /* change type number in reallocation */ size_t obj_size; /* size of each allocated object */ size_t n_ops; /* number of operations */ int parse_mode; /* type of parsing function */ }; /* * obj_tx_bench -- stores variables used in benchmark, passed within functions. */ static struct obj_tx_bench { PMEMobjpool *pop; /* handle to persistent pool */ struct obj_tx_args *obj_args; /* pointer to benchmark arguments */ size_t *random_types; /* array to store random type numbers */ size_t *sizes; /* array to store size of each allocation */ size_t *resizes; /* array to store size of each reallocation */ size_t n_objs; /* number of objects to allocate */ int type_mode; /* type number mode */ int op_mode; /* type of operation */ int lib_mode; /* type of operation used in initialization */ int lib_op; /* type of main operation */ int lib_op_free; /* type of main operation */ int nesting_mode; /* type of nesting in main operation */ fn_num_t n_oid; /* returns object's number in array */ fn_os_off_t fn_off; /* returns offset for proper operation */ /* * fn_type_num gets proper function assigned, depending on the * value of the type_mode argument, which returns proper type number for * each persistent object. Possible functions are: * - type_mode_one, * - type_mode_rand. */ fn_type_num_t fn_type_num; /* * fn_op gets proper array with functions pointer assigned, depending on * function which is tested by benchmark. Possible arrays are: * -alloc_op * -free_op * -realloc_op */ fn_op_t *fn_op; } obj_bench; /* * item -- TOID's structure */ struct item; /* * obj_tx_worker - stores variables used by one thread. */ struct obj_tx_worker { TOID(struct item) * oids; char **items; unsigned tx_level; unsigned max_level; }; /* * offset - stores offset data used in pmemobj_tx_add_range() */ struct offset { uint64_t off; size_t size; }; /* * alloc_dram -- main operations for obj_tx_alloc benchmark in dram mode */ static int alloc_dram(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; obj_worker->items[idx] = (char *)malloc(obj_bench->sizes[idx]); if (obj_worker->items[idx] == NULL) { perror("malloc"); return -1; } return 0; } /* * alloc_pmem -- main operations for obj_tx_alloc benchmark in pmem mode */ static int alloc_pmem(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { size_t type_num = obj_bench->fn_type_num(obj_bench, worker->index, idx); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; if (pmemobj_alloc(obj_bench->pop, &obj_worker->oids[idx].oid, obj_bench->sizes[idx], type_num, NULL, NULL) != 0) { perror("pmemobj_alloc"); return -1; } return 0; } /* * alloc_tx -- main operations for obj_tx_alloc benchmark in tx mode */ static int alloc_tx(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { size_t type_num = obj_bench->fn_type_num(obj_bench, worker->index, idx); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; obj_worker->oids[idx].oid = pmemobj_tx_xalloc( obj_bench->sizes[idx], type_num, POBJ_XALLOC_NO_FLUSH); if (OID_IS_NULL(obj_worker->oids[idx].oid)) { perror("pmemobj_tx_alloc"); return -1; } return 0; } /* * free_dram -- main operations for obj_tx_free benchmark in dram mode */ static int free_dram(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; free(obj_worker->items[idx]); return 0; } /* * free_pmem -- main operations for obj_tx_free benchmark in pmem mode */ static int free_pmem(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; POBJ_FREE(&obj_worker->oids[idx]); return 0; } /* * free_tx -- main operations for obj_tx_free benchmark in tx mode */ static int free_tx(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; TX_FREE(obj_worker->oids[idx]); return 0; } /* * no_free -- exit operation for benchmarks obj_tx_alloc and obj_tx_free * if there is no need to free memory */ static int no_free(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { return 0; } /* * realloc_dram -- main operations for obj_tx_realloc benchmark in dram mode */ static int realloc_dram(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; char *tmp = (char *)realloc(obj_worker->items[idx], obj_bench->resizes[idx]); if (tmp == NULL) { perror("realloc"); return -1; } obj_worker->items[idx] = tmp; return 0; } /* * realloc_pmem -- main operations for obj_tx_realloc benchmark in pmem mode */ static int realloc_pmem(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; size_t type_num = obj_bench->fn_type_num(obj_bench, worker->index, idx); if (obj_bench->obj_args->change_type) type_num++; if (pmemobj_realloc(obj_bench->pop, &obj_worker->oids[idx].oid, obj_bench->resizes[idx], type_num) != 0) { perror("pmemobj_realloc"); return -1; } return 0; } /* * realloc_tx -- main operations for obj_tx_realloc benchmark in tx mode */ static int realloc_tx(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; size_t type_num = obj_bench->fn_type_num(obj_bench, worker->index, idx); if (obj_bench->obj_args->change_type) type_num++; obj_worker->oids[idx].oid = pmemobj_tx_realloc( obj_worker->oids[idx].oid, obj_bench->sizes[idx], type_num); if (OID_IS_NULL(obj_worker->oids[idx].oid)) { perror("pmemobj_tx_realloc"); return -1; } return 0; } /* * add_range_nested_tx -- main operations of the obj_tx_add_range with nesting. */ static int add_range_nested_tx(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { int ret = 0; struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; TX_BEGIN(obj_bench->pop) { if (obj_bench->obj_args->n_ops != obj_worker->tx_level) { size_t n_oid = obj_bench->n_oid(obj_worker->tx_level); struct offset offset = obj_bench->fn_off( obj_bench, obj_worker->tx_level); pmemobj_tx_add_range(obj_worker->oids[n_oid].oid, offset.off, offset.size); obj_worker->tx_level++; ret = add_range_nested_tx(obj_bench, worker, idx); } } TX_ONABORT { fprintf(stderr, "transaction failed\n"); ret = -1; } TX_END return ret; } /* * add_range_tx -- main operations of the obj_tx_add_range without nesting. */ static int add_range_tx(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { int ret = 0; size_t i = 0; struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; TX_BEGIN(obj_bench->pop) { for (i = 0; i < obj_bench->obj_args->n_ops; i++) { size_t n_oid = obj_bench->n_oid(i); struct offset offset = obj_bench->fn_off(obj_bench, i); ret = pmemobj_tx_add_range(obj_worker->oids[n_oid].oid, offset.off, offset.size); } } TX_ONABORT { fprintf(stderr, "transaction failed\n"); ret = -1; } TX_END return ret; } /* * obj_op_sim -- main function for benchmarks which simulates nested * transactions on dram or pmemobj atomic API by calling function recursively. */ static int obj_op_sim(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { int ret = 0; struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; if (obj_worker->max_level == obj_worker->tx_level) { ret = obj_bench->fn_op[obj_bench->lib_op](obj_bench, worker, idx); } else { obj_worker->tx_level++; ret = obj_op_sim(obj_bench, worker, idx); } return ret; } /* * obj_op_tx -- main recursive function for transactional benchmarks */ static int obj_op_tx(struct obj_tx_bench *obj_bench, struct worker_info *worker, size_t idx) { volatile int ret = 0; struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; TX_BEGIN(obj_bench->pop) { if (obj_worker->max_level == obj_worker->tx_level) { ret = obj_bench->fn_op[obj_bench->lib_op](obj_bench, worker, idx); if (obj_bench->op_mode == OP_MODE_ABORT_NESTED) pmemobj_tx_abort(-1); } else { obj_worker->tx_level++; ret = obj_op_tx(obj_bench, worker, idx); if (--obj_worker->tx_level == 0 && obj_bench->op_mode == OP_MODE_ABORT) pmemobj_tx_abort(-1); } } TX_ONABORT { if (obj_bench->op_mode != OP_MODE_ABORT && obj_bench->op_mode != OP_MODE_ABORT_NESTED) { fprintf(stderr, "transaction failed\n"); ret = -1; } } TX_END return ret; } /* * type_mode_one -- always returns 0, as in the mode NUM_MODE_ONE * all of the persistent objects have the same type_number value. */ static size_t type_mode_one(struct obj_tx_bench *obj_bench, size_t worker_idx, size_t op_idx) { return 0; } /* * type_mode_per_thread -- always returns worker index to all of the persistent * object allocated by the same thread have the same type number. */ static size_t type_mode_per_thread(struct obj_tx_bench *obj_bench, size_t worker_idx, size_t op_idx) { return worker_idx; } /* * type_mode_rand -- returns the value from the random_types array assigned * for the specific operation in a specific thread. */ static size_t type_mode_rand(struct obj_tx_bench *obj_bench, size_t worker_idx, size_t op_idx) { return obj_bench->random_types[op_idx]; } /* * parse_op_mode_add_range -- parses command line "--operation" argument * and returns proper op_mode enum value for obj_tx_add_range. */ static enum op_mode parse_op_mode_add_range(const char *arg) { if (strcmp(arg, "basic") == 0) return OP_MODE_ONE_OBJ; else if (strcmp(arg, "one-obj-nested") == 0) return OP_MODE_ONE_OBJ_NESTED; else if (strcmp(arg, "range") == 0) return OP_MODE_ONE_OBJ_RANGE; else if (strcmp(arg, "range-nested") == 0) return OP_MODE_ONE_OBJ_NESTED_RANGE; else if (strcmp(arg, "all-obj") == 0) return OP_MODE_ALL_OBJ; else if (strcmp(arg, "all-obj-nested") == 0) return OP_MODE_ALL_OBJ_NESTED; else return OP_MODE_UNKNOWN; } /* * parse_op_mode -- parses command line "--operation" argument * and returns proper op_mode enum value. */ static enum op_mode parse_op_mode(const char *arg) { if (strcmp(arg, "basic") == 0) return OP_MODE_COMMIT; else if (strcmp(arg, "abort") == 0) return OP_MODE_ABORT; else if (strcmp(arg, "abort-nested") == 0) return OP_MODE_ABORT_NESTED; else return OP_MODE_UNKNOWN; } static fn_op_t alloc_op[] = {alloc_dram, alloc_tx, alloc_pmem}; static fn_op_t free_op[] = {free_dram, free_tx, free_pmem, no_free}; static fn_op_t realloc_op[] = {realloc_dram, realloc_tx, realloc_pmem}; static fn_op_t add_range_op[] = {add_range_tx, add_range_nested_tx}; static fn_parse_t parse_op[] = {parse_op_mode, parse_op_mode_add_range}; static fn_op_t nestings[] = {obj_op_sim, obj_op_tx}; /* * parse_type_num_mode -- converts string to type_num_mode enum */ static enum type_num_mode parse_type_num_mode(const char *arg) { if (strcmp(arg, "one") == 0) return NUM_MODE_ONE; else if (strcmp(arg, "per-thread") == 0) return NUM_MODE_PER_THREAD; else if (strcmp(arg, "rand") == 0) return NUM_MODE_RAND; fprintf(stderr, "unknown type number\n"); return NUM_MODE_UNKNOWN; } /* * parse_lib_mode -- converts string to type_num_mode enum */ static enum lib_mode parse_lib_mode(const char *arg) { if (strcmp(arg, "dram") == 0) return LIB_MODE_DRAM; else if (strcmp(arg, "pmem") == 0) return LIB_MODE_OBJ_ATOMIC; else if (strcmp(arg, "tx") == 0) return LIB_MODE_OBJ_TX; fprintf(stderr, "unknown lib mode\n"); return LIB_MODE_NONE; } static fn_type_num_t type_num_fn[] = {type_mode_one, type_mode_per_thread, type_mode_rand, NULL}; /* * one_num -- returns always the same number. */ static size_t one_num(size_t idx) { return 0; } /* * diff_num -- returns number given as argument. */ static size_t diff_num(size_t idx) { return idx; } /* * off_entire -- returns zero offset. */ static struct offset off_entire(struct obj_tx_bench *obj_bench, size_t idx) { struct offset offset; offset.off = 0; offset.size = obj_bench->sizes[obj_bench->n_oid(idx)]; return offset; } /* * off_range -- returns offset for range in object. */ static struct offset off_range(struct obj_tx_bench *obj_bench, size_t idx) { struct offset offset; offset.size = obj_bench->sizes[0] / obj_bench->obj_args->n_ops; offset.off = offset.size * idx; return offset; } /* * rand_values -- allocates array and if range mode calculates random * values as allocation sizes for each object otherwise populates whole array * with max value. Used only when range flag set. */ static size_t * rand_values(size_t min, size_t max, size_t n_ops) { size_t size = max - min; size_t *sizes = (size_t *)calloc(n_ops, sizeof(size_t)); if (sizes == NULL) { perror("calloc"); return NULL; } for (size_t i = 0; i < n_ops; i++) sizes[i] = max; if (min) { if (min > max) { fprintf(stderr, "Invalid size\n"); free(sizes); return NULL; } for (size_t i = 0; i < n_ops; i++) sizes[i] = (rand() % size) + min; } return sizes; } /* * obj_tx_add_range_op -- main operations of the obj_tx_add_range benchmark. */ static int obj_tx_add_range_op(struct benchmark *bench, struct operation_info *info) { struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)info->worker->priv; if (add_range_op[obj_bench->lib_op](obj_bench, info->worker, info->index) != 0) return -1; obj_worker->tx_level = 0; return 0; } /* * obj_tx_op -- main operation for obj_tx_alloc(), obj_tx_free() and * obj_tx_realloc() benchmarks. */ static int obj_tx_op(struct benchmark *bench, struct operation_info *info) { struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)info->worker->priv; int ret = nestings[obj_bench->nesting_mode](obj_bench, info->worker, info->index); obj_worker->tx_level = 0; return ret; } /* * obj_tx_init_worker -- common part for the worker initialization functions * for transactional benchmarks. */ static int obj_tx_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)calloc(1, sizeof(struct obj_tx_worker)); if (obj_worker == NULL) { perror("calloc"); return -1; } worker->priv = obj_worker; obj_worker->tx_level = 0; obj_worker->max_level = obj_bench->obj_args->nested; if (obj_bench->lib_mode != LIB_MODE_DRAM) obj_worker->oids = (TOID(struct item) *)calloc( obj_bench->n_objs, sizeof(TOID(struct item))); else obj_worker->items = (char **)calloc(obj_bench->n_objs, sizeof(char *)); if (obj_worker->oids == NULL && obj_worker->items == NULL) { free(obj_worker); perror("calloc"); return -1; } return 0; } /* * obj_tx_free_init_worker_alloc_obj -- special part for the worker * initialization function for benchmarks which needs allocated objects * before operation. */ static int obj_tx_init_worker_alloc_obj(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { unsigned i; if (obj_tx_init_worker(bench, args, worker) != 0) return -1; struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; for (i = 0; i < obj_bench->n_objs; i++) { if (alloc_op[obj_bench->lib_mode](obj_bench, worker, i) != 0) goto out; } return 0; out: for (; i > 0; i--) free_op[obj_bench->lib_mode](obj_bench, worker, i - 1); if (obj_bench->lib_mode == LIB_MODE_DRAM) free(obj_worker->items); else free(obj_worker->oids); free(obj_worker); return -1; } /* * obj_tx_exit_worker -- common part for the worker de-initialization. */ static void obj_tx_exit_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); struct obj_tx_worker *obj_worker = (struct obj_tx_worker *)worker->priv; for (unsigned i = 0; i < obj_bench->n_objs; i++) free_op[obj_bench->lib_op_free](obj_bench, worker, i); if (obj_bench->lib_mode == LIB_MODE_DRAM) free(obj_worker->items); else free(obj_worker->oids); free(obj_worker); } /* * obj_tx_add_range_init -- specific part of the obj_tx_add_range * benchmark initialization. */ static int obj_tx_add_range_init(struct benchmark *bench, struct benchmark_args *args) { struct obj_tx_args *obj_args = (struct obj_tx_args *)args->opts; obj_args->parse_mode = PARSE_OP_MODE_ADD_RANGE; if (args->n_ops_per_thread > MAX_OPS) args->n_ops_per_thread = MAX_OPS; if (obj_tx_init(bench, args) != 0) return -1; struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); obj_bench->n_oid = diff_num; if (obj_bench->op_mode < OP_MODE_ALL_OBJ) { obj_bench->n_oid = one_num; obj_bench->n_objs = 1; } obj_bench->fn_off = off_entire; if (obj_bench->op_mode == OP_MODE_ONE_OBJ_RANGE || obj_bench->op_mode == OP_MODE_ONE_OBJ_NESTED_RANGE) { obj_bench->fn_off = off_range; if (args->n_ops_per_thread > args->dsize) args->dsize = args->n_ops_per_thread; obj_bench->sizes[0] = args->dsize; } obj_bench->lib_op = (obj_bench->op_mode == OP_MODE_ONE_OBJ || obj_bench->op_mode == OP_MODE_ALL_OBJ) ? ADD_RANGE_MODE_ONE_TX : ADD_RANGE_MODE_NESTED_TX; return 0; } /* * obj_tx_free_init -- specific part of the obj_tx_free initialization. */ static int obj_tx_free_init(struct benchmark *bench, struct benchmark_args *args) { if (obj_tx_init(bench, args) != 0) return -1; struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); obj_bench->fn_op = free_op; /* * Generally all objects which were allocated during worker * initialization are released in main operation so there is no need to * free them in exit operation. Only exception is situation where * transaction (inside which object is releasing) is aborted. * Then object is not released so there there is necessary to free it * in exit operation. */ if (!(obj_bench->lib_op == LIB_MODE_OBJ_TX && obj_bench->op_mode != OP_MODE_COMMIT)) obj_bench->lib_op_free = LIB_MODE_NONE; return 0; } /* * obj_tx_alloc_init -- specific part of the obj_tx_alloc initialization. */ static int obj_tx_alloc_init(struct benchmark *bench, struct benchmark_args *args) { if (obj_tx_init(bench, args) != 0) return -1; struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); obj_bench->fn_op = alloc_op; /* * Generally all objects which will be allocated during main operation * need to be released. Only exception is situation where transaction * (inside which object is allocating) is aborted. Then object is not * allocated so there is no need to free it in exit operation. */ if (obj_bench->lib_op == LIB_MODE_OBJ_TX && obj_bench->op_mode != OP_MODE_COMMIT) obj_bench->lib_op_free = LIB_MODE_NONE; return 0; } /* * obj_tx_realloc_init -- specific part of the obj_tx_realloc initialization. */ static int obj_tx_realloc_init(struct benchmark *bench, struct benchmark_args *args) { if (obj_tx_init(bench, args) != 0) return -1; struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); obj_bench->resizes = rand_values(obj_bench->obj_args->min_rsize, obj_bench->obj_args->rsize, args->n_ops_per_thread); if (obj_bench->resizes == NULL) { obj_tx_exit(bench, args); return -1; } obj_bench->fn_op = realloc_op; return 0; } /* * obj_tx_init -- common part of the benchmark initialization for transactional * benchmarks in their init functions. Parses command line arguments, set * variables and creates persistent pool. */ int obj_tx_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); pmembench_set_priv(bench, &obj_bench); obj_bench.obj_args = (struct obj_tx_args *)args->opts; obj_bench.obj_args->obj_size = args->dsize; obj_bench.obj_args->n_ops = args->n_ops_per_thread; obj_bench.n_objs = args->n_ops_per_thread; obj_bench.lib_op = obj_bench.obj_args->lib != NULL ? parse_lib_mode(obj_bench.obj_args->lib) : LIB_MODE_OBJ_ATOMIC; if (obj_bench.lib_op == LIB_MODE_NONE) return -1; obj_bench.lib_mode = obj_bench.lib_op == LIB_MODE_DRAM ? LIB_MODE_DRAM : LIB_MODE_OBJ_ATOMIC; obj_bench.lib_op_free = obj_bench.lib_mode; obj_bench.nesting_mode = obj_bench.lib_op == LIB_MODE_OBJ_TX ? NESTING_MODE_TX : NESTING_MODE_SIM; /* * Multiplication by FACTOR prevents from out of memory error * as the actual size of the allocated persistent objects * is always larger than requested. */ size_t dsize = obj_bench.obj_args->rsize > args->dsize ? obj_bench.obj_args->rsize : args->dsize; size_t psize = args->n_ops_per_thread * (dsize + ALLOC_OVERHEAD) * args->n_threads; psize += PMEMOBJ_MIN_POOL; psize = (size_t)(psize * FACTOR); /* * When adding all allocated objects to undo log there is necessary * to prepare larger pool to prevent out of memory error. */ if (obj_bench.op_mode == OP_MODE_ALL_OBJ || obj_bench.op_mode == OP_MODE_ALL_OBJ_NESTED) psize *= 2; obj_bench.op_mode = parse_op[obj_bench.obj_args->parse_mode]( obj_bench.obj_args->operation); if (obj_bench.op_mode == OP_MODE_UNKNOWN) { fprintf(stderr, "operation mode unknown\n"); return -1; } obj_bench.type_mode = parse_type_num_mode(obj_bench.obj_args->type_num); if (obj_bench.type_mode == NUM_MODE_UNKNOWN) return -1; obj_bench.fn_type_num = type_num_fn[obj_bench.type_mode]; if (obj_bench.type_mode == NUM_MODE_RAND) { obj_bench.random_types = rand_values(1, UINT32_MAX, args->n_ops_per_thread); if (obj_bench.random_types == NULL) return -1; } obj_bench.sizes = rand_values(obj_bench.obj_args->min_size, obj_bench.obj_args->obj_size, args->n_ops_per_thread); if (obj_bench.sizes == NULL) goto free_random_types; if (obj_bench.lib_mode == LIB_MODE_DRAM) return 0; /* Create pmemobj pool. */ if (args->is_poolset) { if (args->fsize < psize) { fprintf(stderr, "insufficient size of poolset\n"); goto free_all; } psize = 0; } obj_bench.pop = pmemobj_create(args->fname, LAYOUT_NAME, psize, args->fmode); if (obj_bench.pop == NULL) { perror("pmemobj_create"); goto free_all; } return 0; free_all: free(obj_bench.sizes); free_random_types: if (obj_bench.type_mode == NUM_MODE_RAND) free(obj_bench.random_types); return -1; } /* * obj_tx_exit -- common part for the exit function of the transactional * benchmarks in their exit functions. */ int obj_tx_exit(struct benchmark *bench, struct benchmark_args *args) { struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); if (obj_bench->lib_mode != LIB_MODE_DRAM) pmemobj_close(obj_bench->pop); free(obj_bench->sizes); if (obj_bench->type_mode == NUM_MODE_RAND) free(obj_bench->random_types); return 0; } /* * obj_tx_realloc_exit -- common part for the exit function of the transactional * benchmarks in their exit functions. */ static int obj_tx_realloc_exit(struct benchmark *bench, struct benchmark_args *args) { struct obj_tx_bench *obj_bench = (struct obj_tx_bench *)pmembench_get_priv(bench); free(obj_bench->resizes); return obj_tx_exit(bench, args); } /* Array defining common command line arguments. */ static struct benchmark_clo obj_tx_clo[8]; static struct benchmark_info obj_tx_alloc; static struct benchmark_info obj_tx_free; static struct benchmark_info obj_tx_realloc; static struct benchmark_info obj_tx_add_range; CONSTRUCTOR(pmemobj_tx_costructor) void pmemobj_tx_costructor(void) { obj_tx_clo[0].opt_short = 'T'; obj_tx_clo[0].opt_long = "type-number"; obj_tx_clo[0].descr = "Type number - one, rand, per-thread"; obj_tx_clo[0].def = "one"; obj_tx_clo[0].type = CLO_TYPE_STR; obj_tx_clo[0].off = clo_field_offset(struct obj_tx_args, type_num); obj_tx_clo[1].opt_short = 'O'; obj_tx_clo[1].opt_long = "operation"; obj_tx_clo[1].descr = "Type of operation"; obj_tx_clo[1].def = "basic"; obj_tx_clo[1].off = clo_field_offset(struct obj_tx_args, operation); obj_tx_clo[1].type = CLO_TYPE_STR; obj_tx_clo[2].opt_short = 'm'; obj_tx_clo[2].opt_long = "min-size"; obj_tx_clo[2].type = CLO_TYPE_UINT; obj_tx_clo[2].descr = "Minimum allocation size"; obj_tx_clo[2].off = clo_field_offset(struct obj_tx_args, min_size); obj_tx_clo[2].def = "0"; obj_tx_clo[2].type_uint.size = clo_field_size(struct obj_tx_args, min_size); obj_tx_clo[2].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; obj_tx_clo[2].type_uint.min = 0; obj_tx_clo[2].type_uint.max = UINT_MAX; /* * nclos field in benchmark_info structures is decremented to make this * options available only for obj_tx_alloc, obj_tx_free and * obj_tx_realloc benchmarks. */ obj_tx_clo[3].opt_short = 'L'; obj_tx_clo[3].opt_long = "lib"; obj_tx_clo[3].descr = "Type of library"; obj_tx_clo[3].def = "tx"; obj_tx_clo[3].off = clo_field_offset(struct obj_tx_args, lib); obj_tx_clo[3].type = CLO_TYPE_STR; obj_tx_clo[4].opt_short = 'N'; obj_tx_clo[4].opt_long = "nestings"; obj_tx_clo[4].type = CLO_TYPE_UINT; obj_tx_clo[4].descr = "Number of nested transactions"; obj_tx_clo[4].off = clo_field_offset(struct obj_tx_args, nested); obj_tx_clo[4].def = "0"; obj_tx_clo[4].type_uint.size = clo_field_size(struct obj_tx_args, nested); obj_tx_clo[4].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; obj_tx_clo[4].type_uint.min = 0; obj_tx_clo[4].type_uint.max = MAX_OPS; obj_tx_clo[5].opt_short = 'r'; obj_tx_clo[5].opt_long = "min-rsize"; obj_tx_clo[5].type = CLO_TYPE_UINT; obj_tx_clo[5].descr = "Minimum reallocation size"; obj_tx_clo[5].off = clo_field_offset(struct obj_tx_args, min_rsize); obj_tx_clo[5].def = "0"; obj_tx_clo[5].type_uint.size = clo_field_size(struct obj_tx_args, min_rsize); obj_tx_clo[5].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; obj_tx_clo[5].type_uint.min = 0; obj_tx_clo[5].type_uint.max = UINT_MAX; obj_tx_clo[6].opt_short = 'R'; obj_tx_clo[6].opt_long = "realloc-size"; obj_tx_clo[6].type = CLO_TYPE_UINT; obj_tx_clo[6].descr = "Reallocation size"; obj_tx_clo[6].off = clo_field_offset(struct obj_tx_args, rsize); obj_tx_clo[6].def = "1"; obj_tx_clo[6].type_uint.size = clo_field_size(struct obj_tx_args, rsize); obj_tx_clo[6].type_uint.base = CLO_INT_BASE_DEC | CLO_INT_BASE_HEX; obj_tx_clo[6].type_uint.min = 1; obj_tx_clo[6].type_uint.max = ULONG_MAX; obj_tx_clo[7].opt_short = 'c'; obj_tx_clo[7].opt_long = "changed-type"; obj_tx_clo[7].descr = "Use another type number in " "reallocation than in allocation"; obj_tx_clo[7].type = CLO_TYPE_FLAG; obj_tx_clo[7].off = clo_field_offset(struct obj_tx_args, change_type); obj_tx_alloc.name = "obj_tx_alloc"; obj_tx_alloc.brief = "pmemobj_tx_alloc() benchmark"; obj_tx_alloc.init = obj_tx_alloc_init; obj_tx_alloc.exit = obj_tx_exit; obj_tx_alloc.multithread = true; obj_tx_alloc.multiops = true; obj_tx_alloc.init_worker = obj_tx_init_worker; obj_tx_alloc.free_worker = obj_tx_exit_worker; obj_tx_alloc.operation = obj_tx_op; obj_tx_alloc.measure_time = true; obj_tx_alloc.clos = obj_tx_clo; obj_tx_alloc.nclos = ARRAY_SIZE(obj_tx_clo) - 3; obj_tx_alloc.opts_size = sizeof(struct obj_tx_args); obj_tx_alloc.rm_file = true; obj_tx_alloc.allow_poolset = true; REGISTER_BENCHMARK(obj_tx_alloc); obj_tx_free.name = "obj_tx_free"; obj_tx_free.brief = "pmemobj_tx_free() benchmark"; obj_tx_free.init = obj_tx_free_init; obj_tx_free.exit = obj_tx_exit; obj_tx_free.multithread = true; obj_tx_free.multiops = true; obj_tx_free.init_worker = obj_tx_init_worker_alloc_obj; obj_tx_free.free_worker = obj_tx_exit_worker; obj_tx_free.operation = obj_tx_op; obj_tx_free.measure_time = true; obj_tx_free.clos = obj_tx_clo; obj_tx_free.nclos = ARRAY_SIZE(obj_tx_clo) - 3; obj_tx_free.opts_size = sizeof(struct obj_tx_args); obj_tx_free.rm_file = true; obj_tx_free.allow_poolset = true; REGISTER_BENCHMARK(obj_tx_free); obj_tx_realloc.name = "obj_tx_realloc"; obj_tx_realloc.brief = "pmemobj_tx_realloc() benchmark"; obj_tx_realloc.init = obj_tx_realloc_init; obj_tx_realloc.exit = obj_tx_realloc_exit; obj_tx_realloc.multithread = true; obj_tx_realloc.multiops = true; obj_tx_realloc.init_worker = obj_tx_init_worker_alloc_obj; obj_tx_realloc.free_worker = obj_tx_exit_worker; obj_tx_realloc.operation = obj_tx_op; obj_tx_realloc.measure_time = true; obj_tx_realloc.clos = obj_tx_clo; obj_tx_realloc.nclos = ARRAY_SIZE(obj_tx_clo); obj_tx_realloc.opts_size = sizeof(struct obj_tx_args); obj_tx_realloc.rm_file = true; obj_tx_realloc.allow_poolset = true; REGISTER_BENCHMARK(obj_tx_realloc); obj_tx_add_range.name = "obj_tx_add_range"; obj_tx_add_range.brief = "pmemobj_tx_add_range() benchmark"; obj_tx_add_range.init = obj_tx_add_range_init; obj_tx_add_range.exit = obj_tx_exit; obj_tx_add_range.multithread = true; obj_tx_add_range.multiops = false; obj_tx_add_range.init_worker = obj_tx_init_worker_alloc_obj; obj_tx_add_range.free_worker = obj_tx_exit_worker; obj_tx_add_range.operation = obj_tx_add_range_op; obj_tx_add_range.measure_time = true; obj_tx_add_range.clos = obj_tx_clo; obj_tx_add_range.nclos = ARRAY_SIZE(obj_tx_clo) - 5; obj_tx_add_range.opts_size = sizeof(struct obj_tx_args); obj_tx_add_range.rm_file = true; obj_tx_add_range.allow_poolset = true; REGISTER_BENCHMARK(obj_tx_add_range); } pmdk-1.4.1/src/benchmarks/rpmem_persist.cpp000066400000000000000000000347151331545616200207710ustar00rootroot00000000000000/* * Copyright 2016-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * rpmem_persist.cpp -- rpmem persist benchmarks definition */ #include #include #include #include #include #include #include #include #include #include #include "benchmark.hpp" #include "libpmem.h" #include "librpmem.h" #include "os.h" #include "set.h" #include "util.h" #define CL_ALIGNMENT 64 #define MAX_OFFSET (CL_ALIGNMENT - 1) #define ALIGN_CL(x) (((x) + CL_ALIGNMENT - 1) & ~(CL_ALIGNMENT - 1)) /* * rpmem_args -- benchmark specific command line options */ struct rpmem_args { char *mode; /* operation mode: stat, seq, rand */ bool no_warmup; /* do not do warmup */ bool no_memset; /* do not call memset before each persist */ size_t chunk_size; /* elementary chunk size */ size_t dest_off; /* destination address offset */ }; /* * rpmem_bench -- benchmark context */ struct rpmem_bench { struct rpmem_args *pargs; /* benchmark specific arguments */ size_t *offsets; /* random/sequential address offsets */ size_t n_offsets; /* number of random elements */ int const_b; /* memset() value */ size_t min_size; /* minimum file size */ void *addrp; /* mapped file address */ void *pool; /* memory pool address */ size_t pool_size; /* size of memory pool */ size_t mapped_len; /* mapped length */ RPMEMpool **rpp; /* rpmem pool pointers */ unsigned *nlanes; /* number of lanes for each remote replica */ unsigned nreplicas; /* number of remote replicas */ size_t csize_align; /* aligned elementary chunk size */ }; /* * operation_mode -- mode of operation */ enum operation_mode { OP_MODE_UNKNOWN, OP_MODE_STAT, /* always use the same chunk */ OP_MODE_SEQ, /* use consecutive chunks */ OP_MODE_RAND, /* use random chunks */ OP_MODE_SEQ_WRAP, /* use consequtive chunks, but use file size */ OP_MODE_RAND_WRAP, /* use random chunks, but use file size */ }; /* * parse_op_mode -- parse operation mode from string */ static enum operation_mode parse_op_mode(const char *arg) { if (strcmp(arg, "stat") == 0) return OP_MODE_STAT; else if (strcmp(arg, "seq") == 0) return OP_MODE_SEQ; else if (strcmp(arg, "rand") == 0) return OP_MODE_RAND; else if (strcmp(arg, "seq-wrap") == 0) return OP_MODE_SEQ_WRAP; else if (strcmp(arg, "rand-wrap") == 0) return OP_MODE_RAND_WRAP; else return OP_MODE_UNKNOWN; } /* * init_offsets -- initialize offsets[] array depending on the selected mode */ static int init_offsets(struct benchmark_args *args, struct rpmem_bench *mb, enum operation_mode op_mode) { size_t n_ops_by_size = (mb->pool_size - POOL_HDR_SIZE) / (args->n_threads * mb->csize_align); mb->n_offsets = args->n_ops_per_thread * args->n_threads; mb->offsets = (size_t *)malloc(mb->n_offsets * sizeof(*mb->offsets)); if (!mb->offsets) { perror("malloc"); return -1; } unsigned seed = args->seed; for (size_t i = 0; i < args->n_threads; i++) { for (size_t j = 0; j < args->n_ops_per_thread; j++) { size_t off_idx = i * args->n_ops_per_thread + j; size_t chunk_idx; switch (op_mode) { case OP_MODE_STAT: chunk_idx = i; break; case OP_MODE_SEQ: chunk_idx = i * args->n_ops_per_thread + j; break; case OP_MODE_RAND: chunk_idx = i * args->n_ops_per_thread + os_rand_r(&seed) % args->n_ops_per_thread; break; case OP_MODE_SEQ_WRAP: chunk_idx = i * n_ops_by_size + j % n_ops_by_size; break; case OP_MODE_RAND_WRAP: chunk_idx = i * n_ops_by_size + os_rand_r(&seed) % n_ops_by_size; break; default: assert(0); return -1; } mb->offsets[off_idx] = POOL_HDR_SIZE + chunk_idx * mb->csize_align + mb->pargs->dest_off; } } return 0; } /* * do_warmup -- does the warmup by writing the whole pool area */ static int do_warmup(struct rpmem_bench *mb) { /* clear the entire pool */ memset((char *)mb->pool + POOL_HDR_SIZE, 0, mb->pool_size - POOL_HDR_SIZE); for (unsigned r = 0; r < mb->nreplicas; ++r) { int ret = rpmem_persist(mb->rpp[r], POOL_HDR_SIZE, mb->pool_size - POOL_HDR_SIZE, 0); if (ret) return ret; } /* if no memset for each operation, do one big memset */ if (mb->pargs->no_memset) { memset((char *)mb->pool + POOL_HDR_SIZE, 0xFF, mb->pool_size - POOL_HDR_SIZE); } return 0; } /* * rpmem_op -- actual benchmark operation */ static int rpmem_op(struct benchmark *bench, struct operation_info *info) { struct rpmem_bench *mb = (struct rpmem_bench *)pmembench_get_priv(bench); assert(info->index < mb->n_offsets); uint64_t idx = info->worker->index * info->args->n_ops_per_thread + info->index; size_t offset = mb->offsets[idx]; size_t len = mb->pargs->chunk_size; if (!mb->pargs->no_memset) { void *dest = (char *)mb->pool + offset; /* thread id on MS 4 bits and operation id on LS 4 bits */ int c = ((info->worker->index & 0xf) << 4) + ((0xf & info->index)); memset(dest, c, len); } int ret = 0; for (unsigned r = 0; r < mb->nreplicas; ++r) { assert(info->worker->index < mb->nlanes[r]); ret = rpmem_persist(mb->rpp[r], offset, len, info->worker->index); if (ret) { fprintf(stderr, "rpmem_persist replica #%u: %s\n", r, rpmem_errormsg()); return ret; } } return 0; } /* * rpmem_map_file -- map local file */ static int rpmem_map_file(const char *path, struct rpmem_bench *mb, size_t size) { int mode; #ifndef _WIN32 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; #else mode = S_IWRITE | S_IREAD; #endif mb->addrp = pmem_map_file(path, size, PMEM_FILE_CREATE, mode, &mb->mapped_len, NULL); if (!mb->addrp) return -1; return 0; } /* * rpmem_unmap_file -- unmap local file */ static int rpmem_unmap_file(struct rpmem_bench *mb) { return pmem_unmap(mb->addrp, mb->mapped_len); } /* * rpmem_poolset_init -- read poolset file and initialize benchmark accordingly */ static int rpmem_poolset_init(const char *path, struct rpmem_bench *mb, struct benchmark_args *args) { struct pool_set *set; struct pool_replica *rep; struct remote_replica *remote; struct pool_set_part *part; struct rpmem_pool_attr attr; memset(&attr, 0, sizeof(attr)); memcpy(attr.signature, "PMEMBNCH", sizeof(attr.signature)); /* read and validate poolset */ if (util_poolset_read(&set, path)) { fprintf(stderr, "Invalid poolset file '%s'\n", path); return -1; } assert(set); if (set->nreplicas < 2) { fprintf(stderr, "No replicas defined\n"); goto err_poolset_free; } if (set->remote == 0) { fprintf(stderr, "No remote replicas defined\n"); goto err_poolset_free; } for (unsigned i = 1; i < set->nreplicas; ++i) { if (!set->replica[i]->remote) { fprintf(stderr, "Local replicas are not supported\n"); goto err_poolset_free; } } /* read and validate master replica */ rep = set->replica[0]; assert(rep); assert(rep->remote == NULL); if (rep->nparts != 1) { fprintf(stderr, "Multipart master replicas " "are not supported\n"); goto err_poolset_free; } if (rep->repsize < mb->min_size) { fprintf(stderr, "A master replica is too small (%zu < %zu)\n", rep->repsize, mb->min_size); goto err_poolset_free; } part = (struct pool_set_part *)&rep->part[0]; if (rpmem_map_file(part->path, mb, rep->repsize)) { perror(part->path); goto err_poolset_free; } mb->pool_size = mb->mapped_len; mb->pool = (void *)((uintptr_t)mb->addrp); /* prepare remote replicas */ mb->nreplicas = set->nreplicas - 1; mb->nlanes = (unsigned *)malloc(mb->nreplicas * sizeof(unsigned)); if (mb->nlanes == NULL) { perror("malloc"); goto err_unmap_file; } mb->rpp = (RPMEMpool **)malloc(mb->nreplicas * sizeof(RPMEMpool *)); if (mb->rpp == NULL) { perror("malloc"); goto err_free_lanes; } unsigned r; for (r = 0; r < mb->nreplicas; ++r) { remote = set->replica[r + 1]->remote; assert(remote); mb->nlanes[r] = args->n_threads; /* Temporary WA for librpmem issue */ ++mb->nlanes[r]; mb->rpp[r] = rpmem_create(remote->node_addr, remote->pool_desc, mb->addrp, mb->pool_size, &mb->nlanes[r], &attr); if (!mb->rpp[r]) { perror("rpmem_create"); goto err_rpmem_close; } if (mb->nlanes[r] < args->n_threads) { fprintf(stderr, "Number of threads too large for " "replica #%u (max: %u)\n", r, mb->nlanes[r]); r++; /* close current replica */ goto err_rpmem_close; } } util_poolset_free(set); return 0; err_rpmem_close: for (unsigned i = 0; i < r; i++) rpmem_close(mb->rpp[i]); free(mb->rpp); err_free_lanes: free(mb->nlanes); err_unmap_file: rpmem_unmap_file(mb); err_poolset_free: util_poolset_free(set); return -1; } /* * rpmem_poolset_fini -- close opened local and remote replicas */ static void rpmem_poolset_fini(struct rpmem_bench *mb) { for (unsigned r = 0; r < mb->nreplicas; ++r) { rpmem_close(mb->rpp[r]); } rpmem_unmap_file(mb); } /* * rpmem_set_min_size -- compute minimal file size based on benchmark arguments */ static void rpmem_set_min_size(struct rpmem_bench *mb, enum operation_mode op_mode, struct benchmark_args *args) { mb->csize_align = ALIGN_CL(mb->pargs->chunk_size); switch (op_mode) { case OP_MODE_STAT: mb->min_size = mb->csize_align * args->n_threads; break; case OP_MODE_SEQ: case OP_MODE_RAND: mb->min_size = mb->csize_align * args->n_ops_per_thread * args->n_threads; break; case OP_MODE_SEQ_WRAP: case OP_MODE_RAND_WRAP: /* * at least one chunk per thread to avoid false sharing */ mb->min_size = mb->csize_align * args->n_threads; break; default: assert(0); } mb->min_size += POOL_HDR_SIZE; } /* * rpmem_init -- initialization function */ static int rpmem_init(struct benchmark *bench, struct benchmark_args *args) { assert(bench != NULL); assert(args != NULL); assert(args->opts != NULL); struct rpmem_bench *mb = (struct rpmem_bench *)malloc(sizeof(struct rpmem_bench)); if (!mb) { perror("malloc"); return -1; } mb->pargs = (struct rpmem_args *)args->opts; mb->pargs->chunk_size = args->dsize; enum operation_mode op_mode = parse_op_mode(mb->pargs->mode); if (op_mode == OP_MODE_UNKNOWN) { fprintf(stderr, "Invalid operation mode argument '%s'\n", mb->pargs->mode); goto err_parse_mode; } rpmem_set_min_size(mb, op_mode, args); if (rpmem_poolset_init(args->fname, mb, args)) { goto err_poolset_init; } /* initialize offsets[] array depending on benchmark args */ if (init_offsets(args, mb, op_mode) < 0) { goto err_init_offsets; } if (!mb->pargs->no_warmup) { if (do_warmup(mb) != 0) { fprintf(stderr, "do_warmup() function failed.\n"); goto err_warmup; } } pmembench_set_priv(bench, mb); return 0; err_warmup: free(mb->offsets); err_init_offsets: rpmem_poolset_fini(mb); err_poolset_init: err_parse_mode: free(mb); return -1; } /* * rpmem_exit -- benchmark cleanup function */ static int rpmem_exit(struct benchmark *bench, struct benchmark_args *args) { struct rpmem_bench *mb = (struct rpmem_bench *)pmembench_get_priv(bench); rpmem_poolset_fini(mb); free(mb->offsets); free(mb); return 0; } static struct benchmark_clo rpmem_clo[4]; /* Stores information about benchmark. */ static struct benchmark_info rpmem_info; CONSTRUCTOR(rpmem_persist_costructor) void pmem_rpmem_persist(void) { rpmem_clo[0].opt_short = 'M'; rpmem_clo[0].opt_long = "mem-mode"; rpmem_clo[0].descr = "Memory writing mode :" " stat, seq[-wrap], rand[-wrap]"; rpmem_clo[0].def = "seq"; rpmem_clo[0].off = clo_field_offset(struct rpmem_args, mode); rpmem_clo[0].type = CLO_TYPE_STR; rpmem_clo[1].opt_short = 'D'; rpmem_clo[1].opt_long = "dest-offset"; rpmem_clo[1].descr = "Destination cache line " "alignment offset"; rpmem_clo[1].def = "0"; rpmem_clo[1].off = clo_field_offset(struct rpmem_args, dest_off); rpmem_clo[1].type = CLO_TYPE_UINT; rpmem_clo[1].type_uint.size = clo_field_size(struct rpmem_args, dest_off); rpmem_clo[1].type_uint.base = CLO_INT_BASE_DEC; rpmem_clo[1].type_uint.min = 0; rpmem_clo[1].type_uint.max = MAX_OFFSET; rpmem_clo[2].opt_short = 'w'; rpmem_clo[2].opt_long = "no-warmup"; rpmem_clo[2].descr = "Don't do warmup"; rpmem_clo[2].def = "false"; rpmem_clo[2].type = CLO_TYPE_FLAG; rpmem_clo[2].off = clo_field_offset(struct rpmem_args, no_warmup); rpmem_clo[3].opt_short = 'T'; rpmem_clo[3].opt_long = "no-memset"; rpmem_clo[3].descr = "Don't call memset for all rpmem_persist"; rpmem_clo[3].def = "false"; rpmem_clo[3].off = clo_field_offset(struct rpmem_args, no_memset); rpmem_clo[3].type = CLO_TYPE_FLAG; rpmem_info.name = "rpmem_persist"; rpmem_info.brief = "Benchmark for rpmem_persist() " "operation"; rpmem_info.init = rpmem_init; rpmem_info.exit = rpmem_exit; rpmem_info.multithread = true; rpmem_info.multiops = true; rpmem_info.operation = rpmem_op; rpmem_info.measure_time = true; rpmem_info.clos = rpmem_clo; rpmem_info.nclos = ARRAY_SIZE(rpmem_clo); rpmem_info.opts_size = sizeof(struct rpmem_args); rpmem_info.rm_file = true; rpmem_info.allow_poolset = true; REGISTER_BENCHMARK(rpmem_info); }; pmdk-1.4.1/src/benchmarks/scenario.cpp000066400000000000000000000122061331545616200176720ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * scenario.cpp -- scenario module definitions */ #include #include #include #include "queue.h" #include "scenario.hpp" /* * kv_alloc -- allocate key/value structure */ struct kv * kv_alloc(const char *key, const char *value) { struct kv *kv = (struct kv *)malloc(sizeof(*kv)); assert(kv != NULL); kv->key = strdup(key); assert(kv->key != NULL); kv->value = strdup(value); assert(kv->value != NULL); return kv; } /* * kv_free -- free the key/value structure */ void kv_free(struct kv *kv) { assert(kv != NULL); free(kv->key); free(kv->value); free(kv); } /* * scenario_alloc -- allocate scenario structure */ struct scenario * scenario_alloc(const char *name, const char *bench) { struct scenario *s = (struct scenario *)malloc(sizeof(*s)); assert(s != NULL); TAILQ_INIT(&s->head); s->name = strdup(name); assert(s->name != NULL); s->benchmark = strdup(bench); assert(s->benchmark != NULL); s->group = NULL; return s; } /* * scenario_free -- free the scenario structure and all its content */ void scenario_free(struct scenario *s) { assert(s != NULL); while (!TAILQ_EMPTY(&s->head)) { struct kv *kv = TAILQ_FIRST(&s->head); TAILQ_REMOVE(&s->head, kv, next); kv_free(kv); } free(s->group); free(s->name); free(s->benchmark); free(s); } /* * scenario_set_group -- set group of scenario */ void scenario_set_group(struct scenario *s, const char *group) { assert(s != NULL); s->group = strdup(group); } /* * scenarios_alloc -- allocate scenarios structure */ struct scenarios * scenarios_alloc(void) { struct scenarios *scenarios = (struct scenarios *)malloc(sizeof(*scenarios)); assert(NULL != scenarios); TAILQ_INIT(&scenarios->head); return scenarios; } /* * scenarios_free -- free scenarios structure and all its content */ void scenarios_free(struct scenarios *scenarios) { assert(scenarios != NULL); while (!TAILQ_EMPTY(&scenarios->head)) { struct scenario *sce = TAILQ_FIRST(&scenarios->head); TAILQ_REMOVE(&scenarios->head, sce, next); scenario_free(sce); } free(scenarios); } /* * scenarios_get_scenario -- get scenario of given name */ struct scenario * scenarios_get_scenario(struct scenarios *ss, const char *name) { struct scenario *scenario; FOREACH_SCENARIO(scenario, ss) { if (strcmp(scenario->name, name) == 0) return scenario; } return NULL; } /* * contains_scenarios -- check if cmd line args contain any scenarios from ss */ bool contains_scenarios(int argc, char **argv, struct scenarios *ss) { assert(argv != NULL); assert(argc > 0); assert(ss != NULL); for (int i = 0; i < argc; i++) { if (scenarios_get_scenario(ss, argv[i])) return true; } return false; } /* * clone_scenario -- alloc a new scenario and copy all data from src scenario */ struct scenario * clone_scenario(struct scenario *src_scenario) { assert(src_scenario != NULL); struct scenario *new_scenario = scenario_alloc(src_scenario->name, src_scenario->benchmark); assert(new_scenario != NULL); struct kv *src_kv; FOREACH_KV(src_kv, src_scenario) { struct kv *new_kv = kv_alloc(src_kv->key, src_kv->value); assert(new_kv != NULL); TAILQ_INSERT_TAIL(&new_scenario->head, new_kv, next); } return new_scenario; } /* * find_kv_in_scenario - find a kv in the given scenario with the given key * value. Function returns the pointer to the kv structure containing the key or * NULL if it is not found */ struct kv * find_kv_in_scenario(const char *key, const struct scenario *scenario) { struct kv *kv; FOREACH_KV(kv, scenario) { if (strcmp(kv->key, key) == 0) return kv; } return NULL; } pmdk-1.4.1/src/benchmarks/scenario.hpp000066400000000000000000000052611331545616200177020ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * scenario.hpp -- scenario module declaration */ #include struct kv { TAILQ_ENTRY(kv) next; char *key; char *value; }; struct scenario { TAILQ_ENTRY(scenario) next; TAILQ_HEAD(scenariohead, kv) head; char *name; char *benchmark; char *group; }; struct scenarios { TAILQ_HEAD(scenarioshead, scenario) head; }; #define FOREACH_SCENARIO(s, ss) TAILQ_FOREACH((s), &(ss)->head, next) #define FOREACH_KV(kv, s) TAILQ_FOREACH((kv), &(s)->head, next) struct kv *kv_alloc(const char *key, const char *value); void kv_free(struct kv *kv); struct scenario *scenario_alloc(const char *name, const char *bench); void scenario_free(struct scenario *s); void scenario_set_group(struct scenario *s, const char *group); struct scenarios *scenarios_alloc(void); void scenarios_free(struct scenarios *scenarios); struct scenario *scenarios_get_scenario(struct scenarios *ss, const char *name); bool contains_scenarios(int argc, char **argv, struct scenarios *ss); struct scenario *clone_scenario(struct scenario *src_scenario); struct kv *find_kv_in_scenario(const char *key, const struct scenario *scenario); pmdk-1.4.1/src/benchmarks/vmem.cpp000066400000000000000000000526021331545616200170370ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * vmem.cpp -- vmem_malloc, vmem_free and vmem_realloc multithread benchmarks */ #include "benchmark.hpp" #include #include #include #define DIR_MODE 0700 #define MAX_POOLS 8 #define FACTOR 2 #define RRAND(max, min) (rand() % ((max) - (min)) + (min)) struct vmem_bench; typedef int (*operation)(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx); /* * vmem_args -- additional properties set as arguments opts */ struct vmem_args { bool stdlib_alloc; /* use stdlib allocator instead of vmem */ bool no_warmup; /* do not perform warmup */ bool pool_per_thread; /* create single pool per thread */ ssize_t min_size; /* size of min allocation in range mode */ ssize_t rsize; /* size of reallocation */ ssize_t min_rsize; /* size of min reallocation in range mode */ /* perform operation on object allocated by other thread */ bool mix; }; /* * item -- structure representing single allocated object */ struct item { void *buf; /* buffer for operations */ /* number of pool to which object is assigned */ unsigned pool_num; }; /* * vmem_worker -- additional properties set as worker private */ struct vmem_worker { /* array to store objects used in operations performed by worker */ struct item *objs; unsigned pool_number; /* number of pool used by worker */ }; /* * vmem_bench -- additional properties set as benchmark private */ struct vmem_bench { VMEM **pools; /* handle for VMEM pools */ struct vmem_worker *workers; /* array with private workers data */ size_t pool_size; /* size of each pool */ unsigned npools; /* number of created pools */ size_t *alloc_sizes; /* array with allocation sizes */ size_t *realloc_sizes; /* array with reallocation sizes */ unsigned *mix_ops; /* array with random indexes */ bool rand_alloc; /* use range mode in allocation */ bool rand_realloc; /* use range mode in reallocation */ int lib_mode; /* library mode - vmem or stdlib */ }; /* * lib_mode -- enumeration used to determine mode of the benchmark */ enum lib_mode { VMEM_MODE, STDLIB_MODE }; /* * vmem_malloc_op -- malloc operation using vmem */ static int vmem_malloc_op(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx) { struct item *item = &vb->workers[worker_idx].objs[info_idx]; item->buf = vmem_malloc(vb->pools[item->pool_num], vb->alloc_sizes[info_idx]); if (item->buf == NULL) { perror("vmem_malloc"); return -1; } return 0; } /* * stdlib_malloc_op -- malloc operation using stdlib */ static int stdlib_malloc_op(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx) { struct item *item = &vb->workers[worker_idx].objs[info_idx]; item->buf = malloc(vb->alloc_sizes[info_idx]); if (item->buf == NULL) { perror("malloc"); return -1; } return 0; } /* * vmem_free_op -- free operation using vmem */ static int vmem_free_op(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx) { struct item *item = &vb->workers[worker_idx].objs[info_idx]; if (item->buf != NULL) vmem_free(vb->pools[item->pool_num], item->buf); item->buf = NULL; return 0; } /* * stdlib_free_op -- free operation using stdlib */ static int stdlib_free_op(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx) { struct item *item = &vb->workers[worker_idx].objs[info_idx]; if (item->buf != NULL) free(item->buf); item->buf = NULL; return 0; } /* * vmem_realloc_op -- realloc operation using vmem */ static int vmem_realloc_op(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx) { struct item *item = &vb->workers[worker_idx].objs[info_idx]; item->buf = vmem_realloc(vb->pools[item->pool_num], item->buf, vb->realloc_sizes[info_idx]); if (vb->realloc_sizes[info_idx] != 0 && item->buf == NULL) { perror("vmem_realloc"); return -1; } return 0; } /* * stdlib_realloc_op -- realloc operation using stdlib */ static int stdlib_realloc_op(struct vmem_bench *vb, unsigned worker_idx, size_t info_idx) { struct item *item = &vb->workers[worker_idx].objs[info_idx]; item->buf = realloc(item->buf, vb->realloc_sizes[info_idx]); if (vb->realloc_sizes[info_idx] != 0 && item->buf == NULL) { perror("realloc"); return -1; } return 0; } static operation malloc_op[2] = {vmem_malloc_op, stdlib_malloc_op}; static operation free_op[2] = {vmem_free_op, stdlib_free_op}; static operation realloc_op[2] = {vmem_realloc_op, stdlib_realloc_op}; /* * vmem_create_pools -- use vmem_create to create pools */ static int vmem_create_pools(struct vmem_bench *vb, struct benchmark_args *args) { unsigned i; struct vmem_args *va = (struct vmem_args *)args->opts; size_t dsize = args->dsize + va->rsize; vb->pool_size = dsize * args->n_ops_per_thread * args->n_threads / vb->npools; vb->pools = (VMEM **)calloc(vb->npools, sizeof(VMEM *)); if (vb->pools == NULL) { perror("calloc"); return -1; } if (vb->pool_size < VMEM_MIN_POOL * args->n_threads) vb->pool_size = VMEM_MIN_POOL * args->n_threads; /* multiply pool size to prevent out of memory error */ vb->pool_size *= FACTOR; for (i = 0; i < vb->npools; i++) { vb->pools[i] = vmem_create(args->fname, vb->pool_size); if (vb->pools[i] == NULL) { perror("vmem_create"); goto err; } } return 0; err: for (int j = i - 1; j >= 0; j--) vmem_delete(vb->pools[j]); free(vb->pools); return -1; } /* * random_values -- calculates values for random sizes */ static void random_values(size_t *alloc_sizes, struct benchmark_args *args, size_t max, size_t min) { if (args->seed != 0) srand(args->seed); for (size_t i = 0; i < args->n_ops_per_thread; i++) alloc_sizes[i] = RRAND(max, min); } /* * static_values -- fulls array with the same value */ static void static_values(size_t *alloc_sizes, size_t dsize, size_t nops) { for (size_t i = 0; i < nops; i++) alloc_sizes[i] = dsize; } /* * vmem_do_warmup -- perform warm-up by malloc and free for every thread */ static int vmem_do_warmup(struct vmem_bench *vb, struct benchmark_args *args) { unsigned i; size_t j; int ret = 0; for (i = 0; i < args->n_threads; i++) { for (j = 0; j < args->n_ops_per_thread; j++) { if (malloc_op[vb->lib_mode](vb, i, j) != 0) { ret = -1; fprintf(stderr, "warmup failed"); break; } } for (; j > 0; j--) free_op[vb->lib_mode](vb, i, j - 1); } return ret; } /* * malloc_main_op -- main operations for vmem_malloc benchmark */ static int malloc_main_op(struct benchmark *bench, struct operation_info *info) { struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); return malloc_op[vb->lib_mode](vb, info->worker->index, info->index); } /* * free_main_op -- main operations for vmem_free benchmark */ static int free_main_op(struct benchmark *bench, struct operation_info *info) { struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); return free_op[vb->lib_mode](vb, info->worker->index, info->index); } /* * realloc_main_op -- main operations for vmem_realloc benchmark */ static int realloc_main_op(struct benchmark *bench, struct operation_info *info) { struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); return realloc_op[vb->lib_mode](vb, info->worker->index, info->index); } /* * vmem_mix_op -- main operations for vmem_mix benchmark */ static int vmem_mix_op(struct benchmark *bench, struct operation_info *info) { struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); unsigned idx = vb->mix_ops[info->index]; free_op[vb->lib_mode](vb, info->worker->index, idx); return malloc_op[vb->lib_mode](vb, info->worker->index, idx); } /* * vmem_init_worker_alloc -- initialize worker for vmem_free and * vmem_realloc benchmark when mix flag set to false */ static int vmem_init_worker_alloc(struct vmem_bench *vb, struct benchmark_args *args, struct worker_info *worker) { size_t i; for (i = 0; i < args->n_ops_per_thread; i++) { if (malloc_op[vb->lib_mode](vb, worker->index, i) != 0) goto out; } return 0; out: for (int j = i - 1; j >= 0; j--) free_op[vb->lib_mode](vb, worker->index, i); return -1; } /* * vmem_init_worker_alloc_mix -- initialize worker for vmem_free and * vmem_realloc benchmark when mix flag set to true */ static int vmem_init_worker_alloc_mix(struct vmem_bench *vb, struct benchmark_args *args, struct worker_info *worker) { unsigned i = 0; uint64_t j = 0; size_t idx = 0; size_t ops_per_thread = args->n_ops_per_thread / args->n_threads; for (i = 0; i < args->n_threads; i++) { for (j = 0; j < ops_per_thread; j++) { idx = ops_per_thread * worker->index + j; vb->workers[i].objs[idx].pool_num = vb->workers[i].pool_number; if (malloc_op[vb->lib_mode](vb, i, idx) != 0) goto out; } } for (idx = ops_per_thread * args->n_threads; idx < args->n_ops_per_thread; idx++) { if (malloc_op[vb->lib_mode](vb, worker->index, idx) != 0) goto out_ops; } return 0; out_ops: for (idx--; idx >= ops_per_thread; idx--) free_op[vb->lib_mode](vb, worker->index, idx); out: for (; i > 0; i--) { for (; j > 0; j--) { idx = ops_per_thread * worker->index + j - 1; free_op[vb->lib_mode](vb, i - 1, idx); } } return -1; } /* * vmem_init_worker_alloc_mix -- initialize worker for vmem_free and * vmem_realloc benchmark */ static int vmem_init_worker(struct benchmark *bench, struct benchmark_args *args, struct worker_info *worker) { struct vmem_args *va = (struct vmem_args *)args->opts; struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); int ret = va->mix ? vmem_init_worker_alloc_mix(vb, args, worker) : vmem_init_worker_alloc(vb, args, worker); return ret; } /* * vmem_exit -- function for de-initialization benchmark */ static int vmem_exit(struct benchmark *bench, struct benchmark_args *args) { unsigned i; struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); struct vmem_args *va = (struct vmem_args *)args->opts; if (!va->stdlib_alloc) { for (i = 0; i < vb->npools; i++) { vmem_delete(vb->pools[i]); } free(vb->pools); } for (i = 0; i < args->n_threads; i++) free(vb->workers[i].objs); free(vb->workers); free(vb->alloc_sizes); if (vb->realloc_sizes != NULL) free(vb->realloc_sizes); if (vb->mix_ops != NULL) free(vb->mix_ops); free(vb); return 0; } /* * vmem_exit_free -- frees worker with freeing elements */ static int vmem_exit_free(struct benchmark *bench, struct benchmark_args *args) { struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); for (unsigned i = 0; i < args->n_threads; i++) { for (size_t j = 0; j < args->n_ops_per_thread; j++) { free_op[vb->lib_mode](vb, i, j); } } return vmem_exit(bench, args); } /* * vmem_init -- function for initialization benchmark */ static int vmem_init(struct benchmark *bench, struct benchmark_args *args) { unsigned i; size_t j; assert(bench != NULL); assert(args != NULL); struct vmem_bench *vb = (struct vmem_bench *)calloc(1, sizeof(struct vmem_bench)); if (vb == NULL) { perror("malloc"); return -1; } pmembench_set_priv(bench, vb); struct vmem_worker *vw; struct vmem_args *va = (struct vmem_args *)args->opts; vb->alloc_sizes = NULL; vb->lib_mode = va->stdlib_alloc ? STDLIB_MODE : VMEM_MODE; if (!va->stdlib_alloc && mkdir(args->fname, DIR_MODE) != 0) goto err; vb->npools = va->pool_per_thread ? args->n_threads : 1; vb->rand_alloc = va->min_size != -1; if (vb->rand_alloc && (size_t)va->min_size > args->dsize) { fprintf(stderr, "invalid allocation size\n"); goto err; } /* vmem library is enable to create limited number of pools */ if (va->pool_per_thread && args->n_threads > MAX_POOLS) { fprintf(stderr, "Maximum number of threads is %d for" "pool-per-thread option\n", MAX_POOLS); goto err; } /* initializes buffers for operations for every thread */ vb->workers = (struct vmem_worker *)calloc(args->n_threads, sizeof(struct vmem_worker)); if (vb->workers == NULL) { perror("calloc"); goto err; } for (i = 0; i < args->n_threads; i++) { vw = &vb->workers[i]; vw->objs = (struct item *)calloc(args->n_ops_per_thread, sizeof(struct item)); if (vw->objs == NULL) { perror("calloc"); goto err_free_workers; } vw->pool_number = va->pool_per_thread ? i : 0; for (j = 0; j < args->n_ops_per_thread; j++) vw->objs[j].pool_num = vw->pool_number; } if ((vb->alloc_sizes = (size_t *)malloc( sizeof(size_t) * args->n_ops_per_thread)) == NULL) { perror("malloc"); goto err_free_buf; } if (vb->rand_alloc) random_values(vb->alloc_sizes, args, args->dsize, (size_t)va->min_size); else static_values(vb->alloc_sizes, args->dsize, args->n_ops_per_thread); if (!va->stdlib_alloc && vmem_create_pools(vb, args) != 0) goto err_free_sizes; if (!va->no_warmup && vmem_do_warmup(vb, args) != 0) goto err_free_all; return 0; err_free_all: if (!va->stdlib_alloc) { for (i = 0; i < vb->npools; i++) vmem_delete(vb->pools[i]); free(vb->pools); } err_free_sizes: free(vb->alloc_sizes); err_free_buf: for (j = i; j > 0; j--) free(vb->workers[j - 1].objs); err_free_workers: free(vb->workers); err: free(vb); return -1; } /* * vmem_realloc_init -- function for initialization vmem_realloc benchmark */ static int vmem_realloc_init(struct benchmark *bench, struct benchmark_args *args) { if (vmem_init(bench, args) != 0) return -1; struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); struct vmem_args *va = (struct vmem_args *)args->opts; vb->rand_realloc = va->min_rsize != -1; if (vb->rand_realloc && va->min_rsize > va->rsize) { fprintf(stderr, "invalid reallocation size\n"); goto err; } if ((vb->realloc_sizes = (size_t *)calloc(args->n_ops_per_thread, sizeof(size_t))) == NULL) { perror("calloc"); goto err; } if (vb->rand_realloc) random_values(vb->realloc_sizes, args, (size_t)va->rsize, (size_t)va->min_rsize); else static_values(vb->realloc_sizes, (size_t)va->rsize, args->n_ops_per_thread); return 0; err: vmem_exit(bench, args); return -1; } /* * vmem_mix_init -- function for initialization vmem_realloc benchmark */ static int vmem_mix_init(struct benchmark *bench, struct benchmark_args *args) { if (vmem_init(bench, args) != 0) return -1; size_t i; unsigned idx, tmp; struct vmem_bench *vb = (struct vmem_bench *)pmembench_get_priv(bench); if ((vb->mix_ops = (unsigned *)calloc(args->n_ops_per_thread, sizeof(unsigned))) == NULL) { perror("calloc"); goto err; } for (i = 0; i < args->n_ops_per_thread; i++) vb->mix_ops[i] = i; if (args->seed != 0) srand(args->seed); for (i = 1; i < args->n_ops_per_thread; i++) { idx = RRAND(args->n_ops_per_thread - 1, 0); tmp = vb->mix_ops[idx]; vb->mix_ops[i] = vb->mix_ops[idx]; vb->mix_ops[idx] = tmp; } return 0; err: vmem_exit(bench, args); return -1; } static struct benchmark_info vmem_malloc_bench; static struct benchmark_info vmem_mix_bench; static struct benchmark_info vmem_free_bench; static struct benchmark_info vmem_realloc_bench; static struct benchmark_clo vmem_clo[7]; CONSTRUCTOR(vmem_persist_costructor) void vmem_persist_costructor(void) { vmem_clo[0].opt_short = 'a'; vmem_clo[0].opt_long = "stdlib-alloc"; vmem_clo[0].descr = "Use stdlib allocator"; vmem_clo[0].type = CLO_TYPE_FLAG; vmem_clo[0].off = clo_field_offset(struct vmem_args, stdlib_alloc); vmem_clo[1].opt_short = 'w'; vmem_clo[1].opt_long = "no-warmup"; vmem_clo[1].descr = "Do not perform warmup"; vmem_clo[1].type = CLO_TYPE_FLAG; vmem_clo[1].off = clo_field_offset(struct vmem_args, no_warmup); vmem_clo[2].opt_short = 'p'; vmem_clo[2].opt_long = "pool-per-thread"; vmem_clo[2].descr = "Create separate pool per thread"; vmem_clo[2].type = CLO_TYPE_FLAG; vmem_clo[2].off = clo_field_offset(struct vmem_args, pool_per_thread); vmem_clo[3].opt_short = 'm'; vmem_clo[3].opt_long = "alloc-min"; vmem_clo[3].type = CLO_TYPE_INT; vmem_clo[3].descr = "Min allocation size"; vmem_clo[3].off = clo_field_offset(struct vmem_args, min_size); vmem_clo[3].def = "-1"; vmem_clo[3].type_int.size = clo_field_size(struct vmem_args, min_size); vmem_clo[3].type_int.base = CLO_INT_BASE_DEC; vmem_clo[3].type_int.min = (-1); vmem_clo[3].type_int.max = INT_MAX; /* * number of command line arguments is decremented to make below * options available only for vmem_free and vmem_realloc benchmark */ vmem_clo[4].opt_short = 'T'; vmem_clo[4].opt_long = "mix-thread"; vmem_clo[4].descr = "Reallocate object allocated " "by another thread"; vmem_clo[4].type = CLO_TYPE_FLAG; vmem_clo[4].off = clo_field_offset(struct vmem_args, mix); /* * number of command line arguments is decremented to make below * options available only for vmem_realloc benchmark */ vmem_clo[5].opt_short = 'r'; vmem_clo[5].opt_long = "realloc-size"; vmem_clo[5].type = CLO_TYPE_UINT; vmem_clo[5].descr = "Reallocation size"; vmem_clo[5].off = clo_field_offset(struct vmem_args, rsize); vmem_clo[5].def = "512"; vmem_clo[5].type_uint.size = clo_field_size(struct vmem_args, rsize); vmem_clo[5].type_uint.base = CLO_INT_BASE_DEC; vmem_clo[5].type_uint.min = 0; vmem_clo[5].type_uint.max = ~0; vmem_clo[6].opt_short = 'R'; vmem_clo[6].opt_long = "realloc-min"; vmem_clo[6].type = CLO_TYPE_INT; vmem_clo[6].descr = "Min reallocation size"; vmem_clo[6].off = clo_field_offset(struct vmem_args, min_rsize); vmem_clo[6].def = "-1"; vmem_clo[6].type_int.size = clo_field_size(struct vmem_args, min_rsize); vmem_clo[6].type_int.base = CLO_INT_BASE_DEC; vmem_clo[6].type_int.min = -1; vmem_clo[6].type_int.max = INT_MAX; vmem_malloc_bench.name = "vmem_malloc"; vmem_malloc_bench.brief = "vmem_malloc() benchmark"; vmem_malloc_bench.init = vmem_init; vmem_malloc_bench.exit = vmem_exit_free; vmem_malloc_bench.multithread = true; vmem_malloc_bench.multiops = true; vmem_malloc_bench.init_worker = NULL; vmem_malloc_bench.free_worker = NULL; vmem_malloc_bench.operation = malloc_main_op; vmem_malloc_bench.clos = vmem_clo; vmem_malloc_bench.nclos = ARRAY_SIZE(vmem_clo) - 3; vmem_malloc_bench.opts_size = sizeof(struct vmem_args); vmem_malloc_bench.rm_file = true; vmem_malloc_bench.allow_poolset = false; REGISTER_BENCHMARK(vmem_malloc_bench); vmem_mix_bench.name = "vmem_mix"; vmem_mix_bench.brief = "vmem_malloc() and vmem_free() " "bechmark"; vmem_mix_bench.init = vmem_mix_init; vmem_mix_bench.exit = vmem_exit_free; vmem_mix_bench.multithread = true; vmem_mix_bench.multiops = true; vmem_mix_bench.init_worker = vmem_init_worker; vmem_mix_bench.free_worker = NULL; vmem_mix_bench.operation = vmem_mix_op; vmem_mix_bench.clos = vmem_clo; vmem_mix_bench.nclos = ARRAY_SIZE(vmem_clo) - 3; vmem_mix_bench.opts_size = sizeof(struct vmem_args); vmem_mix_bench.rm_file = true; vmem_mix_bench.allow_poolset = false; REGISTER_BENCHMARK(vmem_mix_bench); vmem_free_bench.name = "vmem_free"; vmem_free_bench.brief = "vmem_free() benchmark"; vmem_free_bench.init = vmem_init; vmem_free_bench.exit = vmem_exit; vmem_free_bench.multithread = true; vmem_free_bench.multiops = true; vmem_free_bench.init_worker = vmem_init_worker; vmem_free_bench.free_worker = NULL; vmem_free_bench.operation = free_main_op; vmem_free_bench.clos = vmem_clo; vmem_free_bench.nclos = ARRAY_SIZE(vmem_clo) - 2; vmem_free_bench.opts_size = sizeof(struct vmem_args); vmem_free_bench.rm_file = true; vmem_free_bench.allow_poolset = false; REGISTER_BENCHMARK(vmem_free_bench); vmem_realloc_bench.name = "vmem_realloc"; vmem_realloc_bench.brief = "Multithread benchmark vmem - " "realloc"; vmem_realloc_bench.init = vmem_realloc_init; vmem_realloc_bench.exit = vmem_exit_free; vmem_realloc_bench.multithread = true; vmem_realloc_bench.multiops = true; vmem_realloc_bench.init_worker = vmem_init_worker; vmem_realloc_bench.free_worker = NULL; vmem_realloc_bench.operation = realloc_main_op; vmem_realloc_bench.clos = vmem_clo; vmem_realloc_bench.nclos = ARRAY_SIZE(vmem_clo); vmem_realloc_bench.opts_size = sizeof(struct vmem_args); vmem_realloc_bench.rm_file = true; vmem_realloc_bench.allow_poolset = false; REGISTER_BENCHMARK(vmem_realloc_bench); }; pmdk-1.4.1/src/common.inc000066400000000000000000000230521331545616200152320ustar00rootroot00000000000000# Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # src/common.inc -- common Makefile rules for PMDK # TOP := $(dir $(lastword $(MAKEFILE_LIST))).. # import user variables ifneq ($(wildcard $(TOP)/user.mk),) include $(TOP)/user.mk endif LN = ln OBJCOPY ?= objcopy MKDIR = mkdir INSTALL = install CP = cp CSTYLE = $(TOP)/utils/cstyle CSTYLEON ?= 0 STYLE_CHECK = $(TOP)/utils/style_check.sh CHECK_SHEBANG = $(TOP)/utils/check-shebang.sh CHECK_OS = $(TOP)/utils/check-os.sh OS_BANNED = $(TOP)/utils/os-banned COVERAGE = 0 PKG_CONFIG ?= pkg-config HEADERS = $(wildcard *.h) $(wildcard *.hpp) ifeq ($(shell command -v clang-format-3.8 > /dev/null && echo y || echo n), y) CLANG_FORMAT ?= clang-format-3.8 else CLANG_FORMAT ?= clang-format endif GCOV_CFLAGS=-fprofile-arcs -ftest-coverage --coverage GCOV_LDFLAGS=-fprofile-arcs -ftest-coverage GCOV_LIBS=-lgcov osdep = $(1)_$(shell uname -s | tr "[:upper:]" "[:lower:]")$(2) get_arch = $(shell $(CC) -dumpmachine | awk -F'[/-]' '{print $$1}') ifeq ($(shell command -v $(PKG_CONFIG) && echo y || echo n), n) $(error $(PKG_CONFIG) not found) endif check_package = $(shell $(PKG_CONFIG) $(1) && echo y || echo n) check_flag = $(shell echo "int main(){return 0;}" |\ $(CC) $(CFLAGS) -Werror $(1) -x c -o /dev/null - 2>/dev/null && echo y || echo n) check_compiler = $(shell $(CC) --version | grep $(1) && echo y || echo n) # Check for issues with older clang compilers which assert on delete persistent<[][]>. check_clang_template_bug = $(shell echo "using namespace pmem::obj; int main() { delete_persistent(make_persistent(2), 2); return 0; }" |\ $(CXX) --std=c++11 -x c++ -I$(TOP)/src/include/ -include libpmemobj++/make_persistent_array.hpp -L$(TOP)/src/debug/ -c -o /dev/null - 2>/dev/null && echo y || echo n) # Check for issues with older gcc compilers which do not expand variadic template # variables in lambda expressions. check_gcc_variadic_template_bug = $(shell echo "void print() {} template void print(const T&, const Args &...arg) {auto f = [&]{ print(arg...);};} int main() {print(1, 2, 3); return 0;}" |\ $(CXX) --std=c++11 -x c++ -o /dev/null - 2>/dev/null && echo y || echo n) check_cxx_flags = $(shell echo "int main(){return 0;}" |\ $(CXX) $(1) -x c++ -o /dev/null - 2>/dev/null && echo y || echo n) CXX_TESTS=$(check_gcc_variadic_template_bug) cxx_ok=$(if $(findstring n,$(CXX_TESTS)),n,y) # This is a workaround for older incompatible versions of libstdc++ and clang. # Please see https://llvm.org/bugs/show_bug.cgi?id=15517 for more info. check_cxx_chrono = $(shell echo "int main(){return 0;}" |\ $(CXX) -std=c++11 -x c++ -include future -o /dev/null - 2>/dev/null && echo y || echo n) check_Wconversion = $(shell echo "long random(void); char test(void); char test(void){char a = 0; char b = 'a'; char ret = random() == 1 ? a : b; return ret;}" |\ $(CC) -c $(CFLAGS) -Wconversion -x c -o /dev/null - 2>/dev/null && echo y || echo n) check_librt = $(shell echo "int main() { struct timespec t; return clock_gettime(CLOCK_MONOTONIC, &t); }" |\ $(CC) $(CFLAGS) -x c -include time.h -o /dev/null - 2>/dev/null && echo y || echo n) install_recursive = $(shell cd $(1) && find . -type f -exec install -m $(2) -D {} $(3)/{} \;) install_recursive_filter = $(shell cd $(1) && find . -type f -name "$(2)" -exec install -m $(3) -D {} $(4)/{} \;) define create-deps @cp $(objdir)/$*.d $(objdir)/.deps/$*.P; \ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ -e '/^$$/ d' -e 's/$$/ :/' < $(objdir)/$*.d >> $(objdir)/.deps/$*.P; \ $(RM) -f $(objdir)/$*.d endef check_defined = \ $(strip $(foreach 1,$1, \ $(call __check_defined,$1,$(strip $(value 2))))) __check_defined = \ $(if $(value $1),, \ $(error Undefined $1$(if $2, ($2)))) export prefix = /usr/local export exec_prefix := $(prefix) export sysconfdir := $(prefix)/etc export datarootdir := $(prefix)/share export mandir := $(datarootdir)/man export docdir := $(datarootdir)/doc export man1dir := $(mandir)/man1 export man3dir := $(mandir)/man3 export man5dir := $(mandir)/man5 export man7dir := $(mandir)/man7 export cstyle_bin := $(CSTYLE) export clang_format_bin := $(CLANG_FORMAT) ifneq ($(wildcard $(exec_prefix)/x86_64-linux-gnu),) LIB_PREFIX ?= x86_64-linux-gnu/lib endif ifneq ($(wildcard $(exec_prefix)/lib64),) LIB_PREFIX ?= lib64 endif LIB_PREFIX ?= lib all: cstyle-%: $(STYLE_CHECK) $* $(wildcard *.[ch]) $(wildcard *.[ch]pp) cstyle: cstyle-check format: cstyle-format ifeq ($(CSTYLEON),1) define check-cstyle @$(STYLE_CHECK) check $1 && if [ "$2" != "" ]; then mkdir -p `dirname $2` && touch $2; fi endef else ifeq ($(CSTYLEON),2) define check-cstyle @$(STYLE_CHECK) check $1 && if [ "$2" != "" ]; then mkdir -p `dirname $2` && touch $2; fi || true endef else define check-cstyle endef endif define check-os $(CHECK_OS) $(OS_BANNED) $(1) $(2) endef # XXX: to allow gcov tool to connect coverage with source code, we have to # use absolute path to source files ifeq ($(COVERAGE),1) define coverage-path `readlink -f $(1)` endef else define coverage-path $(1) endef endif define sub-target-foreach $(1)-$(2): $$(MAKE) -C $1 $2 ifeq ($(3),y) ifeq ($(custom_build),) $$(MAKE) -C $1 $2 DEBUG=1 endif endif endef define sub-target $(foreach f, $(1), $(eval $(call sub-target-foreach, $f,$(2),$(3)))) endef ifneq ($(wildcard $(prefix)/x86_64-linux-gnu),) INC_PREFIX ?= x86_64-linux-gnu/include endif INC_PREFIX ?= include test_build=$(addprefix "-b ", $(TEST_BUILD)) test_type=$(addprefix " -t ", $(TEST_TYPE)) test_fs=$(addprefix " -f ", $(TEST_FS)) test_time=$(addprefix " -o ", $(TEST_TIME)) test_memcheck=$(addprefix " -m ", $(MEMCHECK)) test_pmemcheck=$(addprefix " -p ", $(PMEMCHECK)) test_helgrind=$(addprefix " -e ", $(HELGRIND)) test_drd=$(addprefix " -d ", $(DRD)) test_providers=$(addprefix " -q ", $(TEST_PROVIDERS)) test_pmethods=$(addprefix " -r ", $(TEST_PMETHODS)) ifeq ($(CHECK_POOL),y) test_check_pool=" -c " endif RUNTEST_OPTIONS := "$(test_build)$(test_type)$(test_fs)$(test_time)" RUNTEST_OPTIONS += "$(test_memcheck)$(test_pmemcheck)$(test_helgrind)$(test_drd)" RUNTEST_OPTIONS += "$(test_providers)$(test_pmethods)$(test_check_pool)" export libdir := $(exec_prefix)/$(LIB_PREFIX) export includedir := $(prefix)/$(INC_PREFIX) export pkgconfigdir := $(libdir)/pkgconfig export bindir := $(exec_prefix)/bin export bashcompdir := $(sysconfdir)/bash_completion.d LIBFABRIC_MIN_VERSION := 1.4.2 # Keep in sync with requirements in src/test/unittest/unittest.sh and # utils/docker/images/install-libfabric.sh. export BUILD_RPMEM := $(call check_package, libfabric --atleast-version=$(LIBFABRIC_MIN_VERSION)) ifneq ($(BUILD_RPMEM),y) export BUILD_RPMEM_INFO := libfabric (version >= $(LIBFABRIC_MIN_VERSION)) is missing -- \ see src/librpmem/README for details. endif NDCTL_MIN_VERSION := 60.1 sparse-c = $(shell for c in *.c; do sparse -Wsparse-all -Wno-declaration-after-statement $(CFLAGS) $(INCS) $$c || true; done) ifeq ($(shell uname -s),FreeBSD) GLIBC_CXXFLAGS=-D_GLIBCXX_USE_C99 UNIX98_CFLAGS= OS_INCS=-I$(TOP)/src/freebsd/include -I/usr/local/include OS_LIBS=-L/usr/local/lib LIBDL= LIBUTIL=-lutil LIBUUID=-luuid LIBCXXABI=-lcxxrt LIBNDCTL= OS_DIMM=none else GLIBC_CXXFLAGS= UNIX98_CFLAGS=-D__USE_UNIX98 OS_INCS= OS_LIBS= LIBDL=-ldl LIBUTIL= LIBUUID= LIBCXXABI=-lc++abi # Detect libndctl if not disabled. ifneq ($(NDCTL_ENABLE),n) HAS_NDCTL := $(shell echo "int main() {struct ndctl_cmd *cmd; ndctl_cmd_smart_get_shutdown_count(cmd);return 0;}" | \ $(CC) -x c -include ndctl/libndctl.h -o /dev/null - -lndctl 2>/dev/null && echo y || echo n) HAS_DAXCTL := $(call check_package, libdaxctl --atleast-version $(NDCTL_MIN_VERSION)) endif # If neither disabled or enabled, set it based on libndctl presence. ifeq ($(NDCTL_ENABLE),) ifeq ($(HAS_NDCTL)$(HAS_DAXCTL),yy) export NDCTL_ENABLE=y else export NDCTL_ENABLE=n endif endif ifeq ($(NDCTL_ENABLE),y) ifeq ($(HAS_NDCTL),n) $(error libndctl(version >= $(NDCTL_MIN_VERSION)) is missing -- see README) endif ifeq ($(HAS_DAXCTL),n) $(error libdaxclt(version >= $(NDCTL_MIN_VERSION)) is missing -- see README) endif LIBNDCTL = $(shell $(PKG_CONFIG) --libs libndctl libdaxctl) else LIBNDCTL= endif OS_DIMM=none endif pmdk-1.4.1/src/common/000077500000000000000000000000001331545616200145355ustar00rootroot00000000000000pmdk-1.4.1/src/common/.cstyleignore000066400000000000000000000000101331545616200172340ustar00rootroot00000000000000queue.h pmdk-1.4.1/src/common/Makefile000066400000000000000000000033101331545616200161720ustar00rootroot00000000000000# Copyright 2014-2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # src/common/Makefile -- Makefile for common # LIBRARY_NAME = pmemcommon include pmemcommon.inc SOURCE +=\ plugin.c include ../Makefile.inc CFLAGS += -DUSE_LIBDL pmdk-1.4.1/src/common/common.rc000066400000000000000000000064751331545616200163670ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * common.rc -- common part of PMDK rc files */ #include #include "srcversion.h" #define VERSION(major, minor, build, revision) major, minor, build, revision #ifdef _DEBUG #define VERSION_DEBUG VS_FF_DEBUG #else #define VERSION_DEBUG 0 #endif #ifdef PRERELEASE #define VERSION_PRERELEASE VS_FF_PRERELEASE #else #define VERSION_PRERELEASE 0 #endif #ifdef BUGFIX #define VERSION_PATCHED VS_FF_PATCHED #else #define VERSION_PATCHED 0 #endif #ifdef PRIVATE #define VERSION_PRIVATE VS_FF_PRIVATE #else #define VERSION_PRIVATE 0 #endif #ifdef CUSTOM #define VERSION_SPECIAL VS_FF_SPECIALBUILD #else #define VERSION_SPECIAL 0 #endif #define VERSION_PRIVATEBUILD VS_FF_PRIVATEBUILD #define VER_PATCHED VS_FF_PATCHED VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION(MAJOR, MINOR, BUILD, REVISION) PRODUCTVERSION VERSION(MAJOR, MINOR, BUILD, REVISION) FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS (VERSION_PRIVATEBUILD | VERSION_PRERELEASE | VERSION_DEBUG | VERSION_SPECIAL | VERSION_PATCHED) FILEOS VOS__WINDOWS32 FILETYPE TYPE FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Intel" VALUE "FileDescription", DESCRIPTION VALUE "FileVersion", SRCVERSION VALUE "InternalName", "PMDK" VALUE "LegalCopyright", "Copyright 2014-2017, Intel Corporation" VALUE "OriginalFilename", FILE_NAME VALUE "ProductName", "Persistent Memory Development Kit" VALUE "ProductVersion", SRCVERSION #if VERSION_SPECIAL == VS_FF_SPECIALBUILD VALUE "SpecialBuild", VERSION_CUSTOM_MSG #endif #if VERSION_PRIVATEBUILD == VS_FF_SPECIALBUILD VALUE "PrivateBuild", "Not a release build" #endif END END BLOCK "VarFileInfo" BEGIN /* XXX: Update to UNICODE */ VALUE "Translation", 0x409, 0 END END pmdk-1.4.1/src/common/dlsym.h000066400000000000000000000056701331545616200160460ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * dlsym.h -- dynamic linking utilities with library-specific implementation */ #ifndef PMDK_DLSYM_H #define PMDK_DLSYM_H 1 #include "out.h" #if defined(USE_LIBDL) && !defined(_WIN32) #include /* * util_dlopen -- calls real dlopen() */ static inline void * util_dlopen(const char *filename) { LOG(3, "filename %s", filename); return dlopen(filename, RTLD_NOW); } /* * util_dlerror -- calls real dlerror() */ static inline char * util_dlerror(void) { return dlerror(); } /* * util_dlsym -- calls real dlsym() */ static inline void * util_dlsym(void *handle, const char *symbol) { LOG(3, "handle %p symbol %s", handle, symbol); return dlsym(handle, symbol); } /* * util_dlclose -- calls real dlclose() */ static inline int util_dlclose(void *handle) { LOG(3, "handle %p", handle); return dlclose(handle); } #else /* empty functions */ /* * util_dlopen -- empty function */ static inline void * util_dlopen(const char *filename) { errno = ENOSYS; return NULL; } /* * util_dlerror -- empty function */ static inline char * util_dlerror(void) { errno = ENOSYS; return NULL; } /* * util_dlsym -- empty function */ static inline void * util_dlsym(void *handle, const char *symbol) { errno = ENOSYS; return NULL; } /* * util_dlclose -- empty function */ static inline int util_dlclose(void *handle) { errno = ENOSYS; return 0; } #endif #endif pmdk-1.4.1/src/common/errno_freebsd.h000066400000000000000000000035771331545616200175410ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * errno_freebsd.h -- map Linux errno's to something close on FreeBSD */ #ifndef PMDK_ERRNO_FREEBSD_H #define PMDK_ERRNO_FREEBSD_H 1 #ifdef __FreeBSD__ #define EBADFD EBADF #define ELIBACC EINVAL #define EMEDIUMTYPE EOPNOTSUPP #define ENOMEDIUM ENODEV #define EREMOTEIO EIO #endif #endif /* PMDK_ERRNO_FREEBSD_H */ pmdk-1.4.1/src/common/file.c000066400000000000000000000310221331545616200156160ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * file.c -- file utilities */ #include #include #include #include #include #include #include #include #include #if !defined(_WIN32) && !defined(__FreeBSD__) #include #endif #include "file.h" #include "os.h" #include "out.h" #include "mmap.h" #define DEVICE_DAX_PREFIX "/sys/class/dax" #define MAX_SIZE_LENGTH 64 #define DEVICE_DAX_ZERO_LEN (2 * MEGABYTE) #ifndef _WIN32 /* * device_dax_size -- (internal) checks the size of a given dax device */ static ssize_t device_dax_size(const char *path) { LOG(3, "path \"%s\"", path); os_stat_t st; int olderrno; if (os_stat(path, &st) < 0) { ERR("!stat \"%s\"", path); return -1; } char spath[PATH_MAX]; snprintf(spath, PATH_MAX, "/sys/dev/char/%u:%u/size", os_major(st.st_rdev), os_minor(st.st_rdev)); LOG(4, "device size path \"%s\"", spath); int fd = os_open(spath, O_RDONLY); if (fd < 0) { ERR("!open \"%s\"", spath); return -1; } ssize_t size = -1; char sizebuf[MAX_SIZE_LENGTH + 1]; ssize_t nread; if ((nread = read(fd, sizebuf, MAX_SIZE_LENGTH)) < 0) { ERR("!read"); goto out; } sizebuf[nread] = 0; /* null termination */ char *endptr; olderrno = errno; errno = 0; size = strtoll(sizebuf, &endptr, 0); if (endptr == sizebuf || *endptr != '\n' || ((size == LLONG_MAX || size == LLONG_MIN) && errno == ERANGE)) { ERR("invalid device size %s", sizebuf); size = -1; goto out; } errno = olderrno; out: olderrno = errno; (void) os_close(fd); errno = olderrno; LOG(4, "device size %zu", size); return size; } #endif /* * util_fd_is_device_dax -- check whether the file descriptor is associated * with a device dax */ int util_fd_is_device_dax(int fd) { LOG(3, "fd %d", fd); #ifdef _WIN32 return 0; #else os_stat_t st; int olderrno = errno; int ret = 0; if (fd < 0) { ERR("invalid file descriptor %d", fd); goto out; } if (os_fstat(fd, &st) < 0) { ERR("!fstat"); goto out; } if (!S_ISCHR(st.st_mode)) { LOG(4, "not a character device"); goto out; } char spath[PATH_MAX]; snprintf(spath, PATH_MAX, "/sys/dev/char/%u:%u/subsystem", os_major(st.st_rdev), os_minor(st.st_rdev)); LOG(4, "device subsystem path \"%s\"", spath); char npath[PATH_MAX]; char *rpath = realpath(spath, npath); if (rpath == NULL) { ERR("!realpath \"%s\"", spath); goto out; } ret = strcmp(DEVICE_DAX_PREFIX, rpath) == 0; out: errno = olderrno; LOG(4, "returning %d", ret); return ret; #endif } /* * util_file_is_device_dax -- checks whether the path points to a device dax */ int util_file_is_device_dax(const char *path) { LOG(3, "path \"%s\"", path); #ifdef _WIN32 return 0; #else int olderrno = errno; int ret = 0; if (path == NULL) { ERR("invalid (NULL) path"); goto out; } int fd = os_open(path, O_RDONLY); if (fd < 0) { /* not a problem - 'path' may point to non existent file */ /* LOG(4, "!open \"%s\"", path); */ goto out; } ret = util_fd_is_device_dax(fd); (void) os_close(fd); out: errno = olderrno; LOG(4, "returning %d", ret); return ret; #endif } /* * util_file_get_size -- returns size of a file */ ssize_t util_file_get_size(const char *path) { LOG(3, "path \"%s\"", path); #ifndef _WIN32 if (util_file_is_device_dax(path)) { return device_dax_size(path); } #endif os_stat_t stbuf; if (os_stat(path, &stbuf) < 0) { ERR("!stat \"%s\"", path); return -1; } LOG(4, "file length %zu", stbuf.st_size); return stbuf.st_size; } /* * util_file_map_whole -- maps the entire file into memory */ void * util_file_map_whole(const char *path) { LOG(3, "path \"%s\"", path); int fd; int olderrno; void *addr = NULL; if ((fd = os_open(path, O_RDWR)) < 0) { ERR("!open \"%s\"", path); return NULL; } ssize_t size = util_file_get_size(path); if (size < 0) { LOG(2, "cannot determine file length \"%s\"", path); goto out; } addr = util_map(fd, (size_t)size, MAP_SHARED, 0, 0, NULL); if (addr == NULL) { LOG(2, "failed to map entire file \"%s\"", path); goto out; } out: olderrno = errno; (void) os_close(fd); errno = olderrno; return addr; } /* * util_file_zero -- zeroes the specified region of the file */ int util_file_zero(const char *path, os_off_t off, size_t len) { LOG(3, "path \"%s\" off %ju len %zu", path, off, len); int fd; int olderrno; int ret = 0; if ((fd = os_open(path, O_RDWR)) < 0) { ERR("!open \"%s\"", path); return -1; } ssize_t size = util_file_get_size(path); if (size < 0) { LOG(2, "cannot determine file length \"%s\"", path); ret = -1; goto out; } if (off > size) { LOG(2, "offset beyond file length, %ju > %ju", off, size); ret = -1; goto out; } if ((size_t)off + len > (size_t)size) { LOG(2, "requested size of write goes beyond the file length, " "%zu > %zu", (size_t)off + len, size); LOG(4, "adjusting len to %zu", size - off); len = (size_t)(size - off); } void *addr = util_map(fd, (size_t)size, MAP_SHARED, 0, 0, NULL); if (addr == NULL) { LOG(2, "failed to map entire file \"%s\"", path); ret = -1; goto out; } /* zero initialize the specified region */ memset((char *)addr + off, 0, len); util_unmap(addr, (size_t)size); out: olderrno = errno; (void) os_close(fd); errno = olderrno; return ret; } /* * util_file_pwrite -- writes to a file with an offset */ ssize_t util_file_pwrite(const char *path, const void *buffer, size_t size, os_off_t offset) { LOG(3, "path \"%s\" buffer %p size %zu offset %ju", path, buffer, size, offset); if (!util_file_is_device_dax(path)) { int fd = util_file_open(path, NULL, 0, O_RDWR); if (fd < 0) { LOG(2, "failed to open file \"%s\"", path); return -1; } ssize_t write_len = pwrite(fd, buffer, size, offset); int olderrno = errno; (void) os_close(fd); errno = olderrno; return write_len; } ssize_t file_size = util_file_get_size(path); if (file_size < 0) { LOG(2, "cannot determine file length \"%s\"", path); return -1; } size_t max_size = (size_t)(file_size - offset); if (size > max_size) { LOG(2, "requested size of write goes beyond the file length, " "%zu > %zu", size, max_size); LOG(4, "adjusting size to %zu", max_size); size = max_size; } void *addr = util_file_map_whole(path); if (addr == NULL) { LOG(2, "failed to map entire file \"%s\"", path); return -1; } memcpy(ADDR_SUM(addr, offset), buffer, size); util_unmap(addr, (size_t)file_size); return (ssize_t)size; } /* * util_file_pread -- reads from a file with an offset */ ssize_t util_file_pread(const char *path, void *buffer, size_t size, os_off_t offset) { LOG(3, "path \"%s\" buffer %p size %zu offset %ju", path, buffer, size, offset); if (!util_file_is_device_dax(path)) { int fd = util_file_open(path, NULL, 0, O_RDONLY); if (fd < 0) { LOG(2, "failed to open file \"%s\"", path); return -1; } ssize_t read_len = pread(fd, buffer, size, offset); int olderrno = errno; (void) os_close(fd); errno = olderrno; return read_len; } ssize_t file_size = util_file_get_size(path); if (file_size < 0) { LOG(2, "cannot determine file length \"%s\"", path); return -1; } size_t max_size = (size_t)(file_size - offset); if (size > max_size) { LOG(2, "requested size of read goes beyond the file length, " "%zu > %zu", size, max_size); LOG(4, "adjusting size to %zu", max_size); size = max_size; } void *addr = util_file_map_whole(path); if (addr == NULL) { LOG(2, "failed to map entire file \"%s\"", path); return -1; } memcpy(buffer, ADDR_SUM(addr, offset), size); util_unmap(addr, (size_t)file_size); return (ssize_t)size; } /* * util_file_create -- create a new memory pool file */ int util_file_create(const char *path, size_t size, size_t minsize) { LOG(3, "path \"%s\" size %zu minsize %zu", path, size, minsize); ASSERTne(size, 0); if (size < minsize) { ERR("size %zu smaller than %zu", size, minsize); errno = EINVAL; return -1; } if (((os_off_t)size) < 0) { ERR("invalid size (%zu) for os_off_t", size); errno = EFBIG; return -1; } int fd; int mode; int flags = O_RDWR | O_CREAT | O_EXCL; #ifndef _WIN32 mode = 0; #else mode = S_IWRITE | S_IREAD; flags |= O_BINARY; #endif /* * Create file without any permission. It will be granted once * initialization completes. */ if ((fd = os_open(path, flags, mode)) < 0) { ERR("!open \"%s\"", path); return -1; } if ((errno = os_posix_fallocate(fd, 0, (os_off_t)size)) != 0) { ERR("!posix_fallocate \"%s\", %zu", path, size); goto err; } /* for windows we can't flock until after we fallocate */ if (os_flock(fd, OS_LOCK_EX | OS_LOCK_NB) < 0) { ERR("!flock \"%s\"", path); goto err; } return fd; err: LOG(4, "error clean up"); int oerrno = errno; if (fd != -1) (void) os_close(fd); os_unlink(path); errno = oerrno; return -1; } /* * util_file_open -- open a memory pool file */ int util_file_open(const char *path, size_t *size, size_t minsize, int flags) { LOG(3, "path \"%s\" size %p minsize %zu flags %d", path, size, minsize, flags); int oerrno; int fd; #ifdef _WIN32 flags |= O_BINARY; #endif if ((fd = os_open(path, flags)) < 0) { ERR("!open \"%s\"", path); return -1; } if (os_flock(fd, OS_LOCK_EX | OS_LOCK_NB) < 0) { ERR("!flock \"%s\"", path); (void) os_close(fd); return -1; } if (size || minsize) { if (size) ASSERTeq(*size, 0); ssize_t actual_size = util_file_get_size(path); if (actual_size < 0) { ERR("stat \"%s\": negative size", path); errno = EINVAL; goto err; } if ((size_t)actual_size < minsize) { ERR("size %zu smaller than %zu", (size_t)actual_size, minsize); errno = EINVAL; goto err; } if (size) { *size = (size_t)actual_size; LOG(4, "actual file size %zu", *size); } } return fd; err: oerrno = errno; if (os_flock(fd, OS_LOCK_UN)) ERR("!flock unlock"); (void) os_close(fd); errno = oerrno; return -1; } /* * util_unlink -- unlinks a file or zeroes a device dax */ int util_unlink(const char *path) { LOG(3, "path \"%s\"", path); if (util_file_is_device_dax(path)) { return util_file_zero(path, 0, DEVICE_DAX_ZERO_LEN); } else { #ifdef _WIN32 /* on Windows we can not unlink Read-Only files */ if (os_chmod(path, S_IREAD | S_IWRITE) == -1) { ERR("!chmod \"%s\"", path); return -1; } #endif return os_unlink(path); } } /* * util_unlink_flock -- flocks the file and unlinks it * * The unlink(2) call on a file which is opened and locked using flock(2) * by different process works on linux. Thus in order to forbid removing a * pool when in use by different process we need to flock(2) the pool files * first before unlinking. */ int util_unlink_flock(const char *path) { LOG(3, "path \"%s\"", path); #ifdef WIN32 /* * On Windows it is not possible to unlink the * file if it is flocked. */ return util_unlink(path); #else int fd = util_file_open(path, NULL, 0, O_RDONLY); if (fd < 0) { LOG(2, "failed to open file \"%s\"", path); return -1; } int ret = util_unlink(path); (void) os_close(fd); return ret; #endif } pmdk-1.4.1/src/common/file.h000066400000000000000000000070571331545616200156360ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * file.h -- internal definitions for file module */ #ifndef PMDK_FILE_H #define PMDK_FILE_H 1 #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include "os.h" #ifdef _WIN32 #define NAME_MAX _MAX_FNAME #endif struct file_info { char filename[NAME_MAX + 1]; int is_dir; }; struct dir_handle { const char *path; #ifdef _WIN32 HANDLE handle; char *_file; #else DIR *dirp; #endif }; int util_file_dir_open(struct dir_handle *a, const char *path); int util_file_dir_next(struct dir_handle *a, struct file_info *info); int util_file_dir_close(struct dir_handle *a); int util_file_dir_remove(const char *path); int util_file_is_device_dax(const char *path); int util_fd_is_device_dax(int fd); int util_ddax_region_find(const char *path); ssize_t util_file_get_size(const char *path); size_t util_file_device_dax_alignment(const char *path); void *util_file_map_whole(const char *path); int util_file_zero(const char *path, os_off_t off, size_t len); ssize_t util_file_pread(const char *path, void *buffer, size_t size, os_off_t offset); ssize_t util_file_pwrite(const char *path, const void *buffer, size_t size, os_off_t offset); int util_tmpfile(const char *dir, const char *templ, int flags); int util_is_absolute_path(const char *path); int util_file_create(const char *path, size_t size, size_t minsize); int util_file_open(const char *path, size_t *size, size_t minsize, int flags); int util_unlink(const char *path); int util_unlink_flock(const char *path); int util_file_mkdir(const char *path, mode_t mode); #ifndef _WIN32 #define util_read read #define util_write write #else /* XXX - consider adding an assertion on (count <= UINT_MAX) */ #define util_read(fd, buf, count) read(fd, buf, (unsigned)(count)) #define util_write(fd, buf, count) write(fd, buf, (unsigned)(count)) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif #ifdef __cplusplus } #endif #endif pmdk-1.4.1/src/common/file_posix.c000066400000000000000000000206251331545616200170470ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * file_posix.c -- Posix versions of file APIs */ /* for O_TMPFILE */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "os.h" #include "file.h" #include "out.h" #define MAX_SIZE_LENGTH 64 #define DAX_REGION_ID_LEN 6 /* 5 digits + \0 */ /* * util_tmpfile_mkstemp -- (internal) create temporary file * if O_TMPFILE not supported */ static int util_tmpfile_mkstemp(const char *dir, const char *templ) { /* the templ must start with a path separator */ ASSERTeq(templ[0], '/'); int oerrno; int fd = -1; char *fullname = alloca(strlen(dir) + strlen(templ) + 1); (void) strcpy(fullname, dir); (void) strcat(fullname, templ); sigset_t set, oldset; sigfillset(&set); (void) sigprocmask(SIG_BLOCK, &set, &oldset); mode_t prev_umask = umask(S_IRWXG | S_IRWXO); fd = os_mkstemp(fullname); umask(prev_umask); if (fd < 0) { ERR("!mkstemp"); goto err; } (void) os_unlink(fullname); (void) sigprocmask(SIG_SETMASK, &oldset, NULL); LOG(3, "unlinked file is \"%s\"", fullname); return fd; err: oerrno = errno; (void) sigprocmask(SIG_SETMASK, &oldset, NULL); if (fd != -1) (void) os_close(fd); errno = oerrno; return -1; } /* * util_tmpfile -- create temporary file */ int util_tmpfile(const char *dir, const char *templ, int flags) { LOG(3, "dir \"%s\" template \"%s\" flags %x", dir, templ, flags); /* only O_EXCL is allowed here */ ASSERT(flags == 0 || flags == O_EXCL); #ifdef O_TMPFILE int fd = open(dir, O_TMPFILE | O_RDWR | flags, S_IRUSR | S_IWUSR); /* * Open can fail if underlying file system does not support O_TMPFILE * flag. */ if (fd >= 0) return fd; if (errno != EOPNOTSUPP) { ERR("!open"); return -1; } #endif return util_tmpfile_mkstemp(dir, templ); } /* * util_is_absolute_path -- check if the path is an absolute one */ int util_is_absolute_path(const char *path) { LOG(3, "path: %s", path); if (path[0] == OS_DIR_SEPARATOR) return 1; else return 0; } /* * util_create_mkdir -- creates new dir */ int util_file_mkdir(const char *path, mode_t mode) { LOG(3, "path: %s mode: %o", path, mode); return mkdir(path, mode); } /* * util_file_dir_open -- open a directory */ int util_file_dir_open(struct dir_handle *handle, const char *path) { LOG(3, "handle: %p path: %s", handle, path); handle->dirp = opendir(path); return handle->dirp == NULL; } /* * util_file_dir_next -- read next file in directory */ int util_file_dir_next(struct dir_handle *handle, struct file_info *info) { LOG(3, "handle: %p info: %p", handle, info); struct dirent *d = readdir(handle->dirp); if (d == NULL) return 1; /* break */ info->filename[NAME_MAX] = '\0'; strncpy(info->filename, d->d_name, NAME_MAX + 1); if (info->filename[NAME_MAX] != '\0') return -1; /* filename truncated */ info->is_dir = d->d_type == DT_DIR; return 0; /* continue */ } /* * util_file_dir_close -- close a directory */ int util_file_dir_close(struct dir_handle *handle) { LOG(3, "path: %p", handle); return closedir(handle->dirp); } /* * util_file_dir_remove -- remove directory */ int util_file_dir_remove(const char *path) { LOG(3, "path: %s", path); return rmdir(path); } /* * device_dax_alignment -- (internal) checks the alignment of given Device DAX */ static size_t device_dax_alignment(const char *path) { LOG(3, "path \"%s\"", path); os_stat_t st; int olderrno; if (os_stat(path, &st) < 0) { ERR("!stat \"%s\"", path); return 0; } char spath[PATH_MAX]; snprintf(spath, PATH_MAX, "/sys/dev/char/%u:%u/device/align", os_major(st.st_rdev), os_minor(st.st_rdev)); LOG(4, "device align path \"%s\"", spath); int fd = os_open(spath, O_RDONLY); if (fd < 0) { ERR("!open \"%s\"", spath); return 0; } size_t size = 0; char sizebuf[MAX_SIZE_LENGTH + 1]; ssize_t nread; if ((nread = read(fd, sizebuf, MAX_SIZE_LENGTH)) < 0) { ERR("!read"); goto out; } sizebuf[nread] = 0; /* null termination */ char *endptr; olderrno = errno; errno = 0; /* 'align' is in decimal format */ size = strtoull(sizebuf, &endptr, 10); if (endptr == sizebuf || *endptr != '\n' || (size == ULLONG_MAX && errno == ERANGE)) { ERR("invalid device alignment %s", sizebuf); size = 0; goto out; } /* * If the alignment value is not a power of two, try with * hex format, as this is how it was printed in older kernels. * Just in case someone is using kernel <4.9. */ if ((size & (size - 1)) != 0) { size = strtoull(sizebuf, &endptr, 16); if (endptr == sizebuf || *endptr != '\n' || (size == ULLONG_MAX && errno == ERANGE)) { ERR("invalid device alignment %s", sizebuf); size = 0; goto out; } } errno = olderrno; out: olderrno = errno; (void) os_close(fd); errno = olderrno; LOG(4, "device alignment %zu", size); return size; } /* * util_file_device_dax_alignment -- returns internal Device DAX alignment */ size_t util_file_device_dax_alignment(const char *path) { LOG(3, "path \"%s\"", path); return device_dax_alignment(path); } /* * util_ddax_region_find -- returns Device DAX region id */ int util_ddax_region_find(const char *path) { LOG(3, "path \"%s\"", path); int dax_reg_id_fd; char dax_region_path[PATH_MAX]; char reg_id[DAX_REGION_ID_LEN]; char *end_addr; os_stat_t st; ASSERTne(path, NULL); if (os_stat(path, &st) < 0) { ERR("!stat \"%s\"", path); return -1; } dev_t dev_id = st.st_rdev; unsigned major = os_major(dev_id); unsigned minor = os_minor(dev_id); int ret = snprintf(dax_region_path, PATH_MAX, "/sys/dev/char/%u:%u/device/dax_region/id", major, minor); if (ret < 0) { ERR("!snprintf(%p, %d, /sys/dev/char/%u:%u/device/" "dax_region/id, %u, %u)", dax_region_path, PATH_MAX, major, minor, major, minor); return -1; } if ((dax_reg_id_fd = os_open(dax_region_path, O_RDONLY)) < 0) { LOG(1, "!open(\"%s\", O_RDONLY)", dax_region_path); return -1; } ssize_t len = read(dax_reg_id_fd, reg_id, DAX_REGION_ID_LEN); if (len == -1) { ERR("!read(%d, %p, %d)", dax_reg_id_fd, reg_id, DAX_REGION_ID_LEN); goto err; } else if (len < 2 || reg_id[len - 1] != '\n') { errno = EINVAL; ERR("!read(%d, %p, %d) invalid format", dax_reg_id_fd, reg_id, DAX_REGION_ID_LEN); goto err; } int olderrno = errno; errno = 0; long reg_num = strtol(reg_id, &end_addr, 10); if ((errno == ERANGE && (reg_num == LONG_MAX || reg_num == LONG_MIN)) || (errno != 0 && reg_num == 0)) { ERR("!strtol(%p, %p, 10)", reg_id, end_addr); goto err; } errno = olderrno; if (end_addr == reg_id) { ERR("!strtol(%p, %p, 10) no digits were found", reg_id, end_addr); goto err; } if (*end_addr != '\n') { ERR("!strtol(%s, %s, 10) invalid format", reg_id, end_addr); goto err; } os_close(dax_reg_id_fd); return (int)reg_num; err: os_close(dax_reg_id_fd); return -1; } pmdk-1.4.1/src/common/file_windows.c000066400000000000000000000130241331545616200173720ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * file_windows.c -- Windows emulation of Linux-specific system calls */ /* * XXX - The initial approach to PMDK for Windows port was to minimize the * amount of changes required in the core part of the library, and to avoid * preprocessor conditionals, if possible. For that reason, some of the * Linux system calls that have no equivalents on Windows have been emulated * using Windows API. * Note that it was not a goal to fully emulate POSIX-compliant behavior * of mentioned functions. They are used only internally, so current * implementation is just good enough to satisfy PMDK needs and to make it * work on Windows. */ #include #include #include #include "file.h" #include "out.h" #include "os.h" /* * util_tmpfile -- create a temporary file */ int util_tmpfile(const char *dir, const char *templ, int flags) { LOG(3, "dir \"%s\" template \"%s\" flags %x", dir, templ, flags); /* only O_EXCL is allowed here */ ASSERT(flags == 0 || flags == O_EXCL); int oerrno; int fd = -1; size_t len = strlen(dir) + strlen(templ) + 1; char *fullname = Malloc(sizeof(*fullname) * len); if (fullname == NULL) { ERR("!Malloc"); return -1; } int ret = _snprintf(fullname, len, "%s%s", dir, templ); if (ret < 0 || ret >= len) { ERR("!snprintf"); goto err; } LOG(4, "fullname \"%s\"", fullname); /* * XXX - block signals and modify file creation mask for the time * of mkstmep() execution. Restore previous settings once the file * is created. */ fd = os_mkstemp(fullname); if (fd < 0) { ERR("!os_mkstemp"); goto err; } /* * There is no point to use unlink() here. First, because it does not * work on open files. Second, because the file is created with * O_TEMPORARY flag, and it looks like such temp files cannot be open * from another process, even though they are visible on * the filesystem. */ Free(fullname); return fd; err: Free(fullname); oerrno = errno; if (fd != -1) (void) os_close(fd); errno = oerrno; return -1; } /* * util_is_absolute_path -- check if the path is absolute */ int util_is_absolute_path(const char *path) { LOG(3, "path \"%s\"", path); if (path == NULL || path[0] == '\0') return 0; if (path[0] == '\\' || path[1] == ':') return 1; return 0; } /* * util_file_mkdir -- creates new dir */ int util_file_mkdir(const char *path, mode_t mode) { /* * On windows we cannot create read only dir so mode * parameter is useless. */ UNREFERENCED_PARAMETER(mode); LOG(3, "path: %s mode: %d", path, mode); return _mkdir(path); } /* * util_file_dir_open -- open a directory */ int util_file_dir_open(struct dir_handle *handle, const char *path) { /* init handle */ handle->handle = NULL; handle->path = path; return 0; } /* * util_file_dir_next - read next file in directory */ int util_file_dir_next(struct dir_handle *handle, struct file_info *info) { WIN32_FIND_DATAA data; if (handle->handle == NULL) { handle->handle = FindFirstFileA(handle->path, &data); if (handle->handle == NULL) return 1; } else { if (FindNextFileA(handle->handle, &data) == 0) return 1; } info->filename[NAME_MAX] = '\0'; strncpy(info->filename, data.cFileName, NAME_MAX + 1); if (info->filename[NAME_MAX] != '\0') return -1; /* filename truncated */ info->is_dir = data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY; return 0; } /* * util_file_dir_close -- close a directory */ int util_file_dir_close(struct dir_handle *handle) { return FindClose(handle->handle); } /* * util_file_dir_close -- remove directory */ int util_file_dir_remove(const char *path) { return RemoveDirectoryA(path) == 0 ? -1 : 0; } /* * util_file_device_dax_alignment -- returns internal Device DAX alignment */ size_t util_file_device_dax_alignment(const char *path) { LOG(3, "path \"%s\"", path); return 0; } /* * util_ddax_region_find -- returns DEV dax region id that contains file */ int util_ddax_region_find(const char *path) { LOG(3, "path \"%s\"", path); return -1; } pmdk-1.4.1/src/common/fs.h000066400000000000000000000042311331545616200153160ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fs.h -- file system traversal abstraction layer */ #ifndef PMDK_FS_H #define PMDK_FS_H 1 #include struct fs; enum fs_entry_type { FS_ENTRY_FILE, FS_ENTRY_DIRECTORY, FS_ENTRY_SYMLINK, FS_ENTRY_OTHER, MAX_FS_ENTRY_TYPES }; struct fs_entry { enum fs_entry_type type; const char *name; size_t namelen; const char *path; size_t pathlen; /* the depth of the traversal */ short level; }; struct fs *fs_new(const char *path); void fs_delete(struct fs *f); /* this call invalidates the previous entry */ struct fs_entry *fs_read(struct fs *f); #endif /* PMDK_FS_H */ pmdk-1.4.1/src/common/fs_posix.c000066400000000000000000000056021331545616200165360ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fs_posix.c -- file system traversal Posix implementation */ #include #include "util.h" #include "out.h" #include "vec.h" #include "fs.h" struct fs { FTS *ft; struct fs_entry entry; }; /* * fs_new -- creates fs traversal instance */ struct fs * fs_new(const char *path) { struct fs *f = Zalloc(sizeof(*f)); if (f == NULL) goto error_fs_alloc; const char *paths[2] = {path, NULL}; f->ft = fts_open((char * const *)paths, FTS_COMFOLLOW | FTS_XDEV, NULL); if (f->ft == NULL) goto error_fts_open; return f; error_fts_open: Free(f); error_fs_alloc: return NULL; } /* * fs_read -- reads an entry from the fs path */ struct fs_entry * fs_read(struct fs *f) { FTSENT *entry = fts_read(f->ft); if (entry == NULL) return NULL; switch (entry->fts_info) { case FTS_D: f->entry.type = FS_ENTRY_DIRECTORY; break; case FTS_F: f->entry.type = FS_ENTRY_FILE; break; case FTS_SL: f->entry.type = FS_ENTRY_SYMLINK; break; default: f->entry.type = FS_ENTRY_OTHER; break; } f->entry.name = entry->fts_name; f->entry.namelen = entry->fts_namelen; f->entry.path = entry->fts_path; f->entry.pathlen = entry->fts_pathlen; f->entry.level = entry->fts_level; return &f->entry; } /* * fs_delete -- deletes a fs traversal instance */ void fs_delete(struct fs *f) { fts_close(f->ft); Free(f); } pmdk-1.4.1/src/common/fs_windows.c000066400000000000000000000074261331545616200170740ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fs_windows.c -- file system traversal windows implementation */ #include #include "util.h" #include "out.h" #include "vec.h" #include "fs.h" struct fs { size_t dirlen; WIN32_FIND_DATAW ffd; HANDLE hFind; int first_done; const char *dir; struct fs_entry entry; }; /* * fs_new -- creates fs traversal instance */ struct fs * fs_new(const char *path) { size_t pathlen = strlen(path); char *search_path = Malloc(strlen(path) + sizeof("\\*\0")); if (search_path == NULL) goto error_spath_alloc; strcpy(search_path, path); strcpy(search_path + pathlen, "\\*\0"); wchar_t *pathw = util_toUTF16(search_path); if (pathw == NULL) goto error_path_alloc; struct fs *f = Zalloc(sizeof(*f)); if (f == NULL) goto error_fs_alloc; f->first_done = 0; f->hFind = FindFirstFileW(pathw, &f->ffd); if (f->hFind == INVALID_HANDLE_VALUE) goto error_fff; f->dir = path; f->dirlen = pathlen; util_free_UTF16(pathw); Free(search_path); return f; error_fff: Free(f); error_fs_alloc: util_free_UTF16(pathw); error_path_alloc: Free(search_path); error_spath_alloc: return NULL; } /* * fs_read -- reads an entry from the fs path */ struct fs_entry * fs_read(struct fs *f) { util_free_UTF8((char *)f->entry.name); Free((char *)f->entry.path); f->entry.name = NULL; f->entry.path = NULL; if (f->first_done) { if (FindNextFileW(f->hFind, &f->ffd) == 0) return NULL; } else { f->first_done = 1; } if (f->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) f->entry.type = FS_ENTRY_DIRECTORY; else f->entry.type = FS_ENTRY_FILE; f->entry.name = util_toUTF8(f->ffd.cFileName); if (f->entry.name == NULL) return NULL; f->entry.namelen = strnlen(f->entry.name, MAX_PATH); f->entry.pathlen = f->dirlen + f->entry.namelen + 1; char *path = Zalloc(f->entry.pathlen + 1); if (path == NULL) { util_free_UTF8((char *)f->entry.name); return NULL; } strcpy(path, f->dir); path[f->dirlen] = '\\'; strcpy(path + f->dirlen + 1, f->entry.name); f->entry.path = path; f->entry.level = 1; return &f->entry; } /* * fs_delete -- deletes a fs traversal instance */ void fs_delete(struct fs *f) { util_free_UTF8((char *)f->entry.name); Free((char *)f->entry.path); FindClose(f->hFind); Free(f); } pmdk-1.4.1/src/common/libpmemcommon.vcxproj000066400000000000000000000150661331545616200210200ustar00rootroot00000000000000 Debug x64 Release x64 {492BAA3D-0D5D-478E-9765-500463AE69AA} Win32Proj libpmemcommon 10.0.14393.0 StaticLibrary true v140 NotSet StaticLibrary true v140 NotSet true false .lib $(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); true false .lib $(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); NotUsing Level3 PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) platform.h CompileAsC MultiThreadedDebugDLL false true Console true ntdll.lib;%(AdditionalDependencies) true NotUsing Level3 PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) platform.h CompileAsC MaxSpeed MultiThreadedDLL Default false ProgramDatabase true Console true ntdll.lib;%(AdditionalDependencies) true pmdk-1.4.1/src/common/libpmemcommon.vcxproj.filters000066400000000000000000000071541331545616200224660ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files pmdk-1.4.1/src/common/mmap.c000066400000000000000000000302671331545616200156430ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * mmap.c -- mmap utilities */ #include #include #include #include #include #include #include #include "file.h" #include "queue.h" #include "mmap.h" #include "sys_util.h" #include "os.h" int Mmap_no_random; void *Mmap_hint; static os_rwlock_t Mmap_list_lock; static SORTEDQ_HEAD(map_list_head, map_tracker) Mmap_list = SORTEDQ_HEAD_INITIALIZER(Mmap_list); /* * util_mmap_init -- initialize the mmap utils * * This is called from the library initialization code. */ void util_mmap_init(void) { LOG(3, NULL); util_rwlock_init(&Mmap_list_lock); /* * For testing, allow overriding the default mmap() hint address. * If hint address is defined, it also disables address randomization. */ char *e = os_getenv("PMEM_MMAP_HINT"); if (e) { char *endp; errno = 0; unsigned long long val = strtoull(e, &endp, 16); if (errno || endp == e) { LOG(2, "Invalid PMEM_MMAP_HINT"); } else if (os_access(OS_MAPFILE, R_OK)) { LOG(2, "No /proc, PMEM_MMAP_HINT ignored"); } else { Mmap_hint = (void *)val; Mmap_no_random = 1; LOG(3, "PMEM_MMAP_HINT set to %p", Mmap_hint); } } } /* * util_mmap_fini -- clean up the mmap utils * * This is called before process stop. */ void util_mmap_fini(void) { LOG(3, NULL); util_rwlock_destroy(&Mmap_list_lock); } /* * util_map -- memory map a file * * This is just a convenience function that calls mmap() with the * appropriate arguments and includes our trace points. */ void * util_map(int fd, size_t len, int flags, int rdonly, size_t req_align, int *map_sync) { LOG(3, "fd %d len %zu flags %d rdonly %d req_align %zu map_sync %p", fd, len, flags, rdonly, req_align, map_sync); void *base; void *addr = util_map_hint(len, req_align); if (addr == MAP_FAILED) { ERR("cannot find a contiguous region of given size"); return NULL; } if (req_align) ASSERTeq((uintptr_t)addr % req_align, 0); int proto = rdonly ? PROT_READ : PROT_READ|PROT_WRITE; base = util_map_sync(addr, len, proto, flags, fd, 0, map_sync); if (base == MAP_FAILED) { ERR("!mmap %zu bytes", len); return NULL; } LOG(3, "mapped at %p", base); return base; } /* * util_unmap -- unmap a file * * This is just a convenience function that calls munmap() with the * appropriate arguments and includes our trace points. */ int util_unmap(void *addr, size_t len) { LOG(3, "addr %p len %zu", addr, len); int retval = munmap(addr, len); if (retval < 0) ERR("!munmap"); return retval; } /* * util_map_tmpfile -- reserve space in an unlinked file and memory-map it * * size must be multiple of page size. */ void * util_map_tmpfile(const char *dir, size_t size, size_t req_align) { int oerrno; if (((os_off_t)size) < 0) { ERR("invalid size (%zu) for os_off_t", size); errno = EFBIG; return NULL; } int fd = util_tmpfile(dir, OS_DIR_SEP_STR "vmem.XXXXXX", O_EXCL); if (fd == -1) { LOG(2, "cannot create temporary file in dir %s", dir); goto err; } if ((errno = os_posix_fallocate(fd, 0, (os_off_t)size)) != 0) { ERR("!posix_fallocate"); goto err; } void *base; if ((base = util_map(fd, size, MAP_SHARED, 0, req_align, NULL)) == NULL) { LOG(2, "cannot mmap temporary file"); goto err; } (void) os_close(fd); return base; err: oerrno = errno; if (fd != -1) (void) os_close(fd); errno = oerrno; return NULL; } /* * util_range_ro -- set a memory range read-only */ int util_range_ro(void *addr, size_t len) { LOG(3, "addr %p len %zu", addr, len); uintptr_t uptr; int retval; /* * mprotect requires addr to be a multiple of pagesize, so * adjust addr and len to represent the full 4k chunks * covering the given range. */ /* increase len by the amount we gain when we round addr down */ len += (uintptr_t)addr & (Pagesize - 1); /* round addr down to page boundary */ uptr = (uintptr_t)addr & ~(Pagesize - 1); if ((retval = mprotect((void *)uptr, len, PROT_READ)) < 0) ERR("!mprotect: PROT_READ"); return retval; } /* * util_range_rw -- set a memory range read-write */ int util_range_rw(void *addr, size_t len) { LOG(3, "addr %p len %zu", addr, len); uintptr_t uptr; int retval; /* * mprotect requires addr to be a multiple of pagesize, so * adjust addr and len to represent the full 4k chunks * covering the given range. */ /* increase len by the amount we gain when we round addr down */ len += (uintptr_t)addr & (Pagesize - 1); /* round addr down to page boundary */ uptr = (uintptr_t)addr & ~(Pagesize - 1); if ((retval = mprotect((void *)uptr, len, PROT_READ|PROT_WRITE)) < 0) ERR("!mprotect: PROT_READ|PROT_WRITE"); return retval; } /* * util_range_none -- set a memory range for no access allowed */ int util_range_none(void *addr, size_t len) { LOG(3, "addr %p len %zu", addr, len); uintptr_t uptr; int retval; /* * mprotect requires addr to be a multiple of pagesize, so * adjust addr and len to represent the full 4k chunks * covering the given range. */ /* increase len by the amount we gain when we round addr down */ len += (uintptr_t)addr & (Pagesize - 1); /* round addr down to page boundary */ uptr = (uintptr_t)addr & ~(Pagesize - 1); if ((retval = mprotect((void *)uptr, len, PROT_NONE)) < 0) ERR("!mprotect: PROT_NONE"); return retval; } /* * util_range_comparer -- (internal) compares the two mapping trackers */ static intptr_t util_range_comparer(struct map_tracker *a, struct map_tracker *b) { return ((intptr_t)a->base_addr - (intptr_t)b->base_addr); } /* * util_range_find_unlocked -- (internal) find the map tracker * for given address range * * Returns the first entry at least partially overlapping given range. * It's up to the caller to check whether the entry exactly matches the range, * or if the range spans multiple entries. */ static struct map_tracker * util_range_find_unlocked(uintptr_t addr, size_t len) { LOG(10, "addr 0x%016" PRIxPTR " len %zu", addr, len); uintptr_t end = addr + len; struct map_tracker *mt; SORTEDQ_FOREACH(mt, &Mmap_list, entry) { if (addr < mt->end_addr && (addr >= mt->base_addr || end > mt->base_addr)) goto out; /* break if there is no chance to find matching entry */ if (addr < mt->base_addr) break; } mt = NULL; out: return mt; } /* * util_range_find -- find the map tracker for given address range * the same as util_range_find_unlocked but locked */ struct map_tracker * util_range_find(uintptr_t addr, size_t len) { LOG(10, "addr 0x%016" PRIxPTR " len %zu", addr, len); util_rwlock_rdlock(&Mmap_list_lock); struct map_tracker *mt = util_range_find_unlocked(addr, len); util_rwlock_unlock(&Mmap_list_lock); return mt; } /* * util_range_register -- add a memory range into a map tracking list */ int util_range_register(const void *addr, size_t len, const char *path, enum pmem_map_type type) { LOG(3, "addr %p len %zu path %s type %d", addr, len, path, type); /* check if not tracked already */ ASSERTeq(util_range_find((uintptr_t)addr, len), NULL); struct map_tracker *mt; mt = Malloc(sizeof(struct map_tracker)); if (mt == NULL) { ERR("!Malloc"); return -1; } mt->base_addr = (uintptr_t)addr; mt->end_addr = mt->base_addr + len; mt->type = type; if (type == PMEM_DEV_DAX) mt->region_id = util_ddax_region_find(path); util_rwlock_wrlock(&Mmap_list_lock); SORTEDQ_INSERT(&Mmap_list, mt, entry, struct map_tracker, util_range_comparer); util_rwlock_unlock(&Mmap_list_lock); return 0; } /* * util_range_split -- (internal) remove or split a map tracking entry */ static int util_range_split(struct map_tracker *mt, const void *addrp, const void *endp) { LOG(3, "begin %p end %p", addrp, endp); uintptr_t addr = (uintptr_t)addrp; uintptr_t end = (uintptr_t)endp; ASSERTne(mt, NULL); ASSERTeq(addr % Mmap_align, 0); ASSERTeq(end % Mmap_align, 0); struct map_tracker *mtb = NULL; struct map_tracker *mte = NULL; /* * 1) b e b e * xxxxxxxxxxxxx => xxx.......xxxx - mtb+mte * 2) b e b e * xxxxxxxxxxxxx => xxxxxxx....... - mtb * 3) b e b e * xxxxxxxxxxxxx => ........xxxxxx - mte * 4) b e b e * xxxxxxxxxxxxx => .............. - */ if (addr > mt->base_addr) { /* case #1/2 */ /* new mapping at the beginning */ mtb = Malloc(sizeof(struct map_tracker)); if (mtb == NULL) { ERR("!Malloc"); goto err; } mtb->base_addr = mt->base_addr; mtb->end_addr = (uintptr_t)addr; mtb->region_id = mt->region_id; mtb->type = mt->type; } if (end < mt->end_addr) { /* case #1/3 */ /* new mapping at the end */ mte = Malloc(sizeof(struct map_tracker)); if (mte == NULL) { ERR("!Malloc"); goto err; } mte->base_addr = end; mte->end_addr = mt->end_addr; mte->region_id = mt->region_id; mte->type = mt->type; } SORTEDQ_REMOVE(&Mmap_list, mt, entry); if (mtb) { SORTEDQ_INSERT(&Mmap_list, mtb, entry, struct map_tracker, util_range_comparer); } if (mte) { SORTEDQ_INSERT(&Mmap_list, mte, entry, struct map_tracker, util_range_comparer); } /* free entry for the original mapping */ Free(mt); return 0; err: Free(mtb); Free(mte); return -1; } /* * util_range_unregister -- remove a memory range * from map tracking list * * Remove the region between [begin,end]. If it's in a middle of the existing * mapping, it results in two new map trackers. */ int util_range_unregister(const void *addr, size_t len) { LOG(3, "addr %p len %zu", addr, len); int ret = 0; util_rwlock_wrlock(&Mmap_list_lock); void *end = (char *)addr + len; /* XXX optimize the loop */ struct map_tracker *mt; while ((mt = util_range_find_unlocked((uintptr_t)addr, len)) != NULL) { if (util_range_split(mt, addr, end) != 0) { ret = -1; break; } } util_rwlock_unlock(&Mmap_list_lock); return ret; } /* * util_range_is_pmem -- return true if entire range * is persistent memory */ int util_range_is_pmem(const void *addrp, size_t len) { LOG(10, "addr %p len %zu", addrp, len); uintptr_t addr = (uintptr_t)addrp; int retval = 1; util_rwlock_rdlock(&Mmap_list_lock); do { struct map_tracker *mt = util_range_find(addr, len); if (mt == NULL) { LOG(4, "address not found 0x%016" PRIxPTR, addr); retval = 0; break; } LOG(10, "range found - begin 0x%016" PRIxPTR " end 0x%016" PRIxPTR, mt->base_addr, mt->end_addr); if (mt->base_addr > addr) { LOG(10, "base address doesn't match: " "0x%" PRIxPTR " > 0x%" PRIxPTR, mt->base_addr, addr); retval = 0; break; } uintptr_t map_len = mt->end_addr - addr; if (map_len > len) map_len = len; len -= map_len; addr += map_len; } while (len > 0); util_rwlock_unlock(&Mmap_list_lock); return retval; } pmdk-1.4.1/src/common/mmap.h000066400000000000000000000112041331545616200156360ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * mmap.h -- internal definitions for mmap module */ #ifndef PMDK_MMAP_H #define PMDK_MMAP_H 1 #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include "out.h" #include "queue.h" #include "os.h" extern int Mmap_no_random; extern void *Mmap_hint; extern char *Mmap_mapfile; void *util_map_sync(void *addr, size_t len, int proto, int flags, int fd, os_off_t offset, int *map_sync); void *util_map(int fd, size_t len, int flags, int rdonly, size_t req_align, int *map_sync); int util_unmap(void *addr, size_t len); void *util_map_tmpfile(const char *dir, size_t size, size_t req_align); #ifdef __FreeBSD__ #define MAP_NORESERVE 0 #define OS_MAPFILE "/proc/curproc/map" #else #define OS_MAPFILE "/proc/self/maps" #endif #ifndef MAP_SYNC #define MAP_SYNC 0x80000 #endif #ifndef MAP_SHARED_VALIDATE #define MAP_SHARED_VALIDATE 0x03 #endif /* * macros for micromanaging range protections for the debug version */ #ifdef DEBUG #define RANGE(addr, len, is_dev_dax, type) do {\ if (!is_dev_dax) ASSERT(util_range_##type(addr, len) >= 0);\ } while (0) #else #define RANGE(addr, len, is_dev_dax, type) do {} while (0) #endif #define RANGE_RO(addr, len, is_dev_dax) RANGE(addr, len, is_dev_dax, ro) #define RANGE_RW(addr, len, is_dev_dax) RANGE(addr, len, is_dev_dax, rw) #define RANGE_NONE(addr, len, is_dev_dax) RANGE(addr, len, is_dev_dax, none) /* pmem mapping type */ enum pmem_map_type { PMEM_DEV_DAX, /* device dax */ PMEM_MAP_SYNC, /* mapping with MAP_SYNC flag on dax fs */ MAX_PMEM_TYPE }; /* * this structure tracks the file mappings outstanding per file handle */ struct map_tracker { SORTEDQ_ENTRY(map_tracker) entry; uintptr_t base_addr; uintptr_t end_addr; int region_id; enum pmem_map_type type; #ifdef _WIN32 /* Windows-specific data */ HANDLE FileHandle; HANDLE FileMappingHandle; DWORD Access; os_off_t Offset; size_t FileLen; #endif }; void util_mmap_init(void); void util_mmap_fini(void); int util_range_ro(void *addr, size_t len); int util_range_rw(void *addr, size_t len); int util_range_none(void *addr, size_t len); char *util_map_hint_unused(void *minaddr, size_t len, size_t align); char *util_map_hint(size_t len, size_t req_align); #define MEGABYTE ((uintptr_t)1 << 20) #define GIGABYTE ((uintptr_t)1 << 30) /* * util_map_hint_align -- choose the desired mapping alignment * * Use 2MB/1GB page alignment only if the mapping length is at least * twice as big as the page size. */ static inline size_t util_map_hint_align(size_t len, size_t req_align) { size_t align = Mmap_align; if (req_align) align = req_align; else if (len >= 2 * GIGABYTE) align = GIGABYTE; else if (len >= 4 * MEGABYTE) align = 2 * MEGABYTE; return align; } int util_range_register(const void *addr, size_t len, const char *path, enum pmem_map_type type); int util_range_unregister(const void *addr, size_t len); struct map_tracker *util_range_find(uintptr_t addr, size_t len); int util_range_is_pmem(const void *addr, size_t len); #ifdef __cplusplus } #endif #endif pmdk-1.4.1/src/common/mmap_posix.c000066400000000000000000000154041331545616200170610ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * mmap_posix.c -- memory-mapped files for Posix */ #include #include #include #include "mmap.h" #include "out.h" #include "os.h" #define PROCMAXLEN 2048 /* maximum expected line length in /proc files */ char *Mmap_mapfile = OS_MAPFILE; /* Should be modified only for testing */ #ifdef __FreeBSD__ static const char *sscanf_os = "%p %p"; #else static const char *sscanf_os = "%p-%p"; #endif /* * util_map_hint_unused -- use /proc to determine a hint address for mmap() * * This is a helper function for util_map_hint(). * It opens up /proc/self/maps and looks for the first unused address * in the process address space that is: * - greater or equal 'minaddr' argument, * - large enough to hold range of given length, * - aligned to the specified unit. * * Asking for aligned address like this will allow the DAX code to use large * mappings. It is not an error if mmap() ignores the hint and chooses * different address. */ char * util_map_hint_unused(void *minaddr, size_t len, size_t align) { LOG(3, "minaddr %p len %zu align %zu", minaddr, len, align); ASSERT(align > 0); FILE *fp; if ((fp = os_fopen(Mmap_mapfile, "r")) == NULL) { ERR("!%s", Mmap_mapfile); return MAP_FAILED; } char line[PROCMAXLEN]; /* for fgets() */ char *lo = NULL; /* beginning of current range in maps file */ char *hi = NULL; /* end of current range in maps file */ char *raddr = minaddr; /* ignore regions below 'minaddr' */ if (raddr == NULL) raddr += Pagesize; raddr = (char *)roundup((uintptr_t)raddr, align); while (fgets(line, PROCMAXLEN, fp) != NULL) { /* check for range line */ if (sscanf(line, sscanf_os, &lo, &hi) == 2) { LOG(4, "%p-%p", lo, hi); if (lo > raddr) { if ((uintptr_t)(lo - raddr) >= len) { LOG(4, "unused region of size %zu " "found at %p", lo - raddr, raddr); break; } else { LOG(4, "region is too small: %zu < %zu", lo - raddr, len); } } if (hi > raddr) { raddr = (char *)roundup((uintptr_t)hi, align); LOG(4, "nearest aligned addr %p", raddr); } if (raddr == NULL) { LOG(4, "end of address space reached"); break; } } } /* * Check for a case when this is the last unused range in the address * space, but is not large enough. (very unlikely) */ if ((raddr != NULL) && (UINTPTR_MAX - (uintptr_t)raddr < len)) { LOG(4, "end of address space reached"); raddr = MAP_FAILED; } fclose(fp); LOG(3, "returning %p", raddr); return raddr; } /* * util_map_hint -- determine hint address for mmap() * * If PMEM_MMAP_HINT environment variable is not set, we let the system to pick * the randomized mapping address. Otherwise, a user-defined hint address * is used. * * ALSR in 64-bit Linux kernel uses 28-bit of randomness for mmap * (bit positions 12-39), which means the base mapping address is randomized * within [0..1024GB] range, with 4KB granularity. Assuming additional * 1GB alignment, it results in 1024 possible locations. * * Configuring the hint address via PMEM_MMAP_HINT environment variable * disables address randomization. In such case, the function will search for * the first unused, properly aligned region of given size, above the specified * address. */ char * util_map_hint(size_t len, size_t req_align) { LOG(3, "len %zu req_align %zu", len, req_align); char *hint_addr = MAP_FAILED; /* choose the desired alignment based on the requested length */ size_t align = util_map_hint_align(len, req_align); if (Mmap_no_random) { LOG(4, "user-defined hint %p", (void *)Mmap_hint); hint_addr = util_map_hint_unused((void *)Mmap_hint, len, align); } else { /* * Create dummy mapping to find an unused region of given size. * Request for increased size for later address alignment. * Use MAP_PRIVATE with read-only access to simulate * zero cost for overcommit accounting. Note: MAP_NORESERVE * flag is ignored if overcommit is disabled (mode 2). */ char *addr = mmap(NULL, len + align, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (addr != MAP_FAILED) { LOG(4, "system choice %p", addr); hint_addr = (char *)roundup((uintptr_t)addr, align); munmap(addr, len + align); } } LOG(4, "hint %p", hint_addr); return hint_addr; } /* * util_map_sync -- memory map given file into memory, if MAP_SHARED flag is * provided it attempts to use MAP_SYNC flag. Otherwise it fallbacks to * mmap(2). */ void * util_map_sync(void *addr, size_t len, int proto, int flags, int fd, os_off_t offset, int *map_sync) { LOG(15, "addr %p len %zu proto %x flags %x fd %d offset %ld " "map_sync %p", addr, len, proto, flags, fd, offset, map_sync); if (map_sync) *map_sync = 0; /* if map_sync is NULL do not even try to mmap with MAP_SYNC flag */ if (!map_sync || flags & MAP_PRIVATE) return mmap(addr, len, proto, flags, fd, offset); /* MAP_SHARED */ void *ret = mmap(addr, len, proto, flags | MAP_SHARED_VALIDATE | MAP_SYNC, fd, offset); if (ret != MAP_FAILED) { LOG(4, "mmap with MAP_SYNC succeeded"); *map_sync = 1; return ret; } if (errno == EINVAL || errno == ENOTSUP) { LOG(4, "mmap with MAP_SYNC not supported"); return mmap(addr, len, proto, flags, fd, offset); } /* other error */ return MAP_FAILED; } pmdk-1.4.1/src/common/mmap_windows.c000066400000000000000000000115061331545616200174100ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * Copyright (c) 2015-2017, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * mmap_windows.c -- memory-mapped files for Windows */ #include #include "mmap.h" #include "out.h" /* * util_map_hint_unused -- use VirtualQuery to determine hint address * * This is a helper function for util_map_hint(). * It iterates thru memory regions and looks for the first unused address * in the process address space that is: * - greater or equal 'minaddr' argument, * - large enough to hold range of given length, * - aligned to the specified unit. */ char * util_map_hint_unused(void *minaddr, size_t len, size_t align) { LOG(3, "minaddr %p len %zu align %zu", minaddr, len, align); ASSERT(align > 0); MEMORY_BASIC_INFORMATION mi; char *lo = NULL; /* beginning of current range in maps file */ char *hi = NULL; /* end of current range in maps file */ char *raddr = minaddr; /* ignore regions below 'minaddr' */ if (raddr == NULL) raddr += Pagesize; raddr = (char *)roundup((uintptr_t)raddr, align); while ((uintptr_t)raddr < UINTPTR_MAX - len) { size_t ret = VirtualQuery(raddr, &mi, sizeof(mi)); if (ret == 0) { ERR("VirtualQuery %p", raddr); return MAP_FAILED; } LOG(4, "addr %p len %zu state %d", mi.BaseAddress, mi.RegionSize, mi.State); if ((mi.State != MEM_FREE) || (mi.RegionSize < len)) { raddr = (char *)mi.BaseAddress + mi.RegionSize; raddr = (char *)roundup((uintptr_t)raddr, align); LOG(4, "nearest aligned addr %p", raddr); } else { LOG(4, "unused region of size %zu found at %p", mi.RegionSize, mi.BaseAddress); return mi.BaseAddress; } } LOG(4, "end of address space reached"); return MAP_FAILED; } /* * util_map_hint -- determine hint address for mmap() * * XXX - Windows doesn't support large DAX pages yet, so there is * no point in aligning for the same. */ char * util_map_hint(size_t len, size_t req_align) { LOG(3, "len %zu req_align %zu", len, req_align); char *hint_addr = MAP_FAILED; /* choose the desired alignment based on the requested length */ size_t align = util_map_hint_align(len, req_align); if (Mmap_no_random) { LOG(4, "user-defined hint %p", (void *)Mmap_hint); hint_addr = util_map_hint_unused((void *)Mmap_hint, len, align); } else { /* * Create dummy mapping to find an unused region of given size. * Request for increased size for later address alignment. * * Use MAP_NORESERVE flag to only reserve the range of pages * rather than commit. We don't want the pages to be actually * backed by the operating system paging file, as the swap * file is usually too small to handle terabyte pools. */ char *addr = mmap(NULL, len + align, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); if (addr != MAP_FAILED) { LOG(4, "system choice %p", addr); hint_addr = (char *)roundup((uintptr_t)addr, align); munmap(addr, len + align); } } LOG(4, "hint %p", hint_addr); return hint_addr; } /* * util_map_sync -- memory map given file into memory */ void * util_map_sync(void *addr, size_t len, int proto, int flags, int fd, os_off_t offset, int *map_sync) { LOG(15, "addr %p len %zu proto %x flags %x fd %d offset %ld", addr, len, proto, flags, fd, offset); if (map_sync) *map_sync = 0; return mmap(addr, len, proto, flags, fd, offset); } pmdk-1.4.1/src/common/os.h000066400000000000000000000073071331545616200153360ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os.h -- os abstaction layer */ #ifndef PMDK_OS_H #define PMDK_OS_H 1 #ifdef __cplusplus extern "C" { #endif #include #include #include #include "errno_freebsd.h" #ifndef _WIN32 #define OS_DIR_SEPARATOR '/' #define OS_DIR_SEP_STR "/" #else #define OS_DIR_SEPARATOR '\\' #define OS_DIR_SEP_STR "\\" #endif #ifndef _WIN32 /* madvise() */ #ifdef __FreeBSD__ #define os_madvise minherit #define MADV_DONTFORK INHERIT_NONE #else #define os_madvise madvise #endif /* dlopen() */ #ifdef __FreeBSD__ #define RTLD_DEEPBIND 0 /* XXX */ #endif /* major(), minor() */ #ifdef __FreeBSD__ #define os_major (unsigned)major #define os_minor (unsigned)minor #else #define os_major major #define os_minor minor #endif #endif /* #ifndef _WIN32 */ struct iovec; /* os_flock */ #define OS_LOCK_SH 1 #define OS_LOCK_EX 2 #define OS_LOCK_NB 4 #define OS_LOCK_UN 8 #ifndef _WIN32 typedef struct stat os_stat_t; #define os_fstat fstat #define os_lseek lseek #else typedef struct _stat64 os_stat_t; #define os_fstat _fstat64 #define os_lseek _lseeki64 #endif #define os_close close #define os_fclose fclose #ifndef _WIN32 typedef off_t os_off_t; #else /* XXX: os_off_t defined in platform.h */ #endif int os_open(const char *pathname, int flags, ...); int os_stat(const char *pathname, os_stat_t *buf); int os_unlink(const char *pathname); int os_access(const char *pathname, int mode); FILE *os_fopen(const char *pathname, const char *mode); FILE *os_fdopen(int fd, const char *mode); int os_chmod(const char *pathname, mode_t mode); int os_mkstemp(char *temp); int os_posix_fallocate(int fd, os_off_t offset, os_off_t len); int os_ftruncate(int fd, os_off_t length); int os_flock(int fd, int operation); ssize_t os_writev(int fd, const struct iovec *iov, int iovcnt); int os_clock_gettime(int id, struct timespec *ts); int os_rand_r(unsigned *seedp); int os_unsetenv(const char *name); int os_setenv(const char *name, const char *value, int overwrite); char *os_getenv(const char *name); const char *os_strsignal(int sig); /* * XXX: missing APis (used in ut_file.c) * * rename * read * write */ #ifdef __cplusplus } #endif #endif /* os.h */ pmdk-1.4.1/src/common/os_auto_flush.h000066400000000000000000000033621331545616200175640ustar00rootroot00000000000000/* * Copyright 2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_auto_flush.h -- abstraction layer for auto flush detection functionality */ #ifndef PMDK_OS_AUTO_FLUSH_H #define PMDK_OS_AUTO_FLUSH_H 1 int os_auto_flush(void); #endif pmdk-1.4.1/src/common/os_auto_flush_linux.c000066400000000000000000000130351331545616200207740ustar00rootroot00000000000000/* * Copyright 2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_auto_flush_linux.c -- Linux abstraction layer for auto flush detection */ #define _GNU_SOURCE #include #include #include #include #include "out.h" #include "os.h" #include "fs.h" #include "os_auto_flush.h" #define BUS_DEVICE_PATH "/sys/bus/nd/devices" #define PERSISTENCE_DOMAIN "persistence_domain" #define DOMAIN_VALUE_LEN 32 /* * check_cpu_cache -- (internal) check if file contains "cpu_cache" entry */ static int check_cpu_cache(const char *domain_path) { LOG(3, "domain_path: %s", domain_path); char domain_value[DOMAIN_VALUE_LEN]; int domain_fd; int cpu_cache = 0; if ((domain_fd = os_open(domain_path, O_RDONLY)) < 0) { LOG(1, "!open(\"%s\", O_RDONLY)", domain_path); goto end; } ssize_t len = read(domain_fd, domain_value, DOMAIN_VALUE_LEN); if (len == -1) { ERR("!read(%d, %p, %d)", domain_fd, domain_value, DOMAIN_VALUE_LEN); cpu_cache = -1; goto end; } else if (domain_value[len - 1] != '\n') { ERR("!read(%d, %p, %d) invalid format", domain_fd, domain_value, DOMAIN_VALUE_LEN); cpu_cache = -1; goto end; } LOG(15, "detected persistent_domain: %s", domain_value); if (strncmp(domain_value, "cpu_cache", strlen("cpu_cache")) == 0) { LOG(15, "cpu_cache in persistent_domain: %s", domain_path); cpu_cache = 1; } else { LOG(15, "cpu_cache not in persistent_domain: %s", domain_path); cpu_cache = 0; } end: if (domain_fd >= 0) os_close(domain_fd); return cpu_cache; } /* * check_domain_in_region -- (internal) check if region * contains persistence_domain file */ static int check_domain_in_region(const char *region_path) { LOG(3, "region_path: %s", region_path); struct fs *reg = NULL; struct fs_entry *reg_entry; char domain_path[PATH_MAX]; int cpu_cache = 0; reg = fs_new(region_path); if (reg == NULL) { ERR("!fs_new: \"%s\"", region_path); cpu_cache = -1; goto end; } while ((reg_entry = fs_read(reg)) != NULL) { /* * persistence_domain has to be a file type entry * and it has to be first level child for region; * there is no need to run into deeper levels */ if (reg_entry->type != FS_ENTRY_FILE || strcmp(reg_entry->name, PERSISTENCE_DOMAIN) != 0 || reg_entry->level != 1) continue; int ret = snprintf(domain_path, PATH_MAX, "%s/"PERSISTENCE_DOMAIN, region_path); if (ret < 0) { ERR("!snprintf(%p, %d," "%s/"PERSISTENCE_DOMAIN", %s)", domain_path, PATH_MAX, region_path, region_path); cpu_cache = -1; goto end; } cpu_cache = check_cpu_cache(domain_path); } end: if (reg) fs_delete(reg); return cpu_cache; } /* * os_auto_flush -- check if platform supports auto flush for all regions * * Traverse "/sys/bus/nd/devices" path to find all the nvdimm regions, * then for each region checks if "persistence_domain" file exists and * contains "cpu_cache" string. * If for any region "persistence_domain" entry does not exists, or its * context is not as expected, assume eADR is not available on this platform. */ int os_auto_flush(void) { LOG(15, NULL); char *device_path; int cpu_cache = 0; device_path = BUS_DEVICE_PATH; os_stat_t sdev; if (os_stat(device_path, &sdev) != 0 || S_ISDIR(sdev.st_mode) == 0) { LOG(3, "eADR not supported"); return cpu_cache; } struct fs *dev = fs_new(device_path); if (dev == NULL) { ERR("!fs_new: \"%s\"", device_path); return -1; } struct fs_entry *dev_entry; while ((dev_entry = fs_read(dev)) != NULL) { /* * Skip if not a symlink, because we expect that * region on sysfs path is a symlink. * Skip if depth is different than 1, bacause region * we are interested in should be the first level * child for device. */ if ((dev_entry->type != FS_ENTRY_SYMLINK) || !strstr(dev_entry->name, "region") || dev_entry->level != 1) continue; LOG(15, "Start traversing region: %s", dev_entry->path); cpu_cache = check_domain_in_region(dev_entry->path); if (cpu_cache != 1) goto end; } end: fs_delete(dev); return cpu_cache; } pmdk-1.4.1/src/common/os_auto_flush_windows.c000066400000000000000000000035771331545616200213410ustar00rootroot00000000000000/* * Copyright 2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_auto_flush_windows.c -- Windows abstraction layer for auto flush detection */ #include #include "out.h" #include "os.h" /* * os_auto_flush -- check if platform supports auto flush * XXX - for now Windows implementation always returns 0 */ int os_auto_flush(void) { LOG(15, NULL); return 0; } pmdk-1.4.1/src/common/os_badblock.h000066400000000000000000000046421331545616200171560ustar00rootroot00000000000000/* * Copyright 2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_badblock.h -- linux bad block API */ #ifndef PMDK_BADBLOCK_H #define PMDK_BADBLOCK_H 1 #include #include #define B2SEC(n) ((n) >> 9) /* convert bytes to sectors */ #define SEC2B(n) ((n) << 9) /* convert sectors to bytes */ /* * 'struct badblock' is already defined in ndctl/libndctl.h, * so we cannot use this name */ struct bad_block { unsigned long long offset; /* in bytes */ unsigned length; /* in bytes */ }; struct badblocks { unsigned long long ns_resource; /* address of the namespace */ unsigned bb_cnt; /* number of bad blocks */ struct bad_block *bbv; /* array of bad blocks */ }; long os_badblocks_count(const char *path); int os_badblocks_get(const char *file, struct badblocks *bbs); int os_badblocks_clear(const char *path); int os_badblocks_check_file(const char *path); #endif /* PMDK_BADBLOCK_H */ pmdk-1.4.1/src/common/os_deep.h000066400000000000000000000036451331545616200163340ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_deep.h -- abstraction layer for common usage of deep_* functions */ #ifndef PMDK_OS_DEEP_PERSIST_H #define PMDK_OS_DEEP_PERSIST_H 1 #include #include #include "set.h" int os_range_deep_common(uintptr_t addr, size_t len); int os_part_deep_common(struct pool_set_part *part, void *addr, size_t len, int flush); #endif pmdk-1.4.1/src/common/os_deep_linux.c000066400000000000000000000127611331545616200175450ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_deep_linux.c -- Linux abstraction layer */ #define _GNU_SOURCE #include #include #include #include "out.h" #include "os.h" #include "mmap.h" #include "file.h" #include "libpmem.h" #include "os_deep.h" /* * os_deep_flush_write -- (internal) perform write to deep_flush file * on given region_id */ static int os_deep_flush_write(int region_id) { LOG(3, "region_id %d", region_id); char deep_flush_path[PATH_MAX]; int deep_flush_fd; snprintf(deep_flush_path, PATH_MAX, "/sys/bus/nd/devices/region%d/deep_flush", region_id); if ((deep_flush_fd = os_open(deep_flush_path, O_WRONLY)) < 0) { LOG(1, "!os_open(\"%s\", O_WRONLY)", deep_flush_path); return -1; } if (write(deep_flush_fd, "1", 1) != 1) { LOG(1, "!write(%d, \"1\")", deep_flush_fd); int oerrno = errno; os_close(deep_flush_fd); errno = oerrno; return -1; } os_close(deep_flush_fd); return 0; } /* * os_deep_type -- (internal) perform deep operation based on a pmem * mapping type */ static int os_deep_type(const struct map_tracker *mt, void *addr, size_t len) { LOG(15, "mt %p addr %p len %zu", mt, addr, len); switch (mt->type) { case PMEM_DEV_DAX: pmem_drain(); if (os_deep_flush_write(mt->region_id) < 0) { if (errno == ENOENT) { errno = ENOTSUP; LOG(1, "!deep_flush not supported"); } else { LOG(2, "cannot write to deep_flush" "in region %d", mt->region_id); } return -1; } return 0; case PMEM_MAP_SYNC: return pmem_msync((void *)addr, len); default: ASSERT(0); return -1; } } /* * os_range_deep_common -- perform deep action of given address range */ int os_range_deep_common(uintptr_t addr, size_t len) { LOG(3, "addr 0x%016" PRIxPTR " len %zu", addr, len); while (len != 0) { const struct map_tracker *mt = util_range_find(addr, len); /* no more overlapping track regions or NOT a device DAX */ if (mt == NULL) { LOG(15, "pmem_msync addr %p, len %lu", (void *)addr, len); return pmem_msync((void *)addr, len); } /* * For range that intersects with the found mapping * write to (Device DAX) deep_flush file. * Call msync for the non-intersecting part. */ if (mt->base_addr > addr) { size_t curr_len = mt->base_addr - addr; if (curr_len > len) curr_len = len; if (pmem_msync((void *)addr, curr_len) != 0) return -1; len -= curr_len; if (len == 0) return 0; addr = mt->base_addr; } size_t mt_in_len = mt->end_addr - addr; size_t persist_len = MIN(len, mt_in_len); if (os_deep_type(mt, (void *)addr, persist_len)) return -1; if (mt->end_addr >= addr + len) return 0; len -= mt_in_len; addr = mt->end_addr; } return 0; } /* * os_part_deep_common -- common function to handle both; * deep_persist and deep_drain part flush cases. * * During deep_persist for part on device DAX it search * device region id, then flushes CPU cache, does SFENCE * and performs WPQ flush on found device DAX region. * * During deep_drain for part on device DAX it search * device region id, then does SFENCE * and performs WPQ flush on found device DAX region. * * In case of parts not on device DAX it calls msync on the range. */ int os_part_deep_common(struct pool_set_part *part, void *addr, size_t len, int flush) { LOG(3, "part %p addr %p len %lu flush %d", part, addr, len, flush); if (part->is_dev_dax) { int region_id = util_ddax_region_find(part->path); if (region_id < 0) { if (errno == ENOENT) { errno = ENOTSUP; LOG(1, "!deep_flush not supported"); } else { LOG(1, "invalid dax_region id %d", region_id); } return -1; } if (flush) { LOG(15, "pmem_deep_flush addr %p, len %lu", addr, len); pmem_deep_flush(addr, len); } pmem_drain(); if (os_deep_flush_write(region_id)) { LOG(1, "ddax_deep_flush_write(%d)", region_id); return -1; } } else { if (pmem_msync(addr, len)) { LOG(1, "pmem_msync(%p, %lu)", addr, len); return -1; } } return 0; } pmdk-1.4.1/src/common/os_deep_windows.c000066400000000000000000000042711331545616200200750ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_deep_windows.c -- Windows abstraction layer for deep_* functions */ #include #include "out.h" #include "os.h" #include "libpmem.h" /* * os_range_deep_common -- call msnyc for non DEV dax */ int os_range_deep_common(uintptr_t addr, size_t len) { LOG(3, "os_range_deep_common addr %p len %lu", addr, len); return pmem_msync((void *)addr, len); } /* * os_part_deep_common -- call msync for non DEV dax */ int os_part_deep_common(struct pool_set_part *part, void *addr, size_t len, int flush) { LOG(3, "part %p addr %p len %lu flush %d", part, addr, len, flush); return pmem_msync(addr, len); } pmdk-1.4.1/src/common/os_dimm.h000066400000000000000000000036651331545616200163470ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_dimm.h -- DIMMs API based on the ndctl library */ #include #include #include "os_badblock.h" int os_dimm_uid(const char *path, char *uid, size_t *len); int os_dimm_usc(const char *path, uint64_t *usc); int os_dimm_files_namespace_badblocks(const char *path, struct badblocks *bbs); int os_dimm_devdax_clear_badblocks(const char *path); pmdk-1.4.1/src/common/os_dimm_ndctl.c000066400000000000000000000346061331545616200175250ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_dimm_ndctl.c -- implementation of DIMMs API based on the ndctl library */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include /* XXX: workaround for missing PAGE_SIZE - should be fixed in linux/ndctl.h */ #include #include #include "out.h" #include "os.h" #include "os_dimm.h" #include "os_badblock.h" /* * http://pmem.io/documents/NVDIMM_DSM_Interface-V1.6.pdf * Table 3-2 SMART amd Health Data - Validity flags * Bit[5] – If set to 1, indicates that Unsafe Shutdown Count * field is valid */ #define USC_VALID_FLAG (1 << 5) #define FOREACH_BUS_REGION_NAMESPACE(ctx, bus, region, ndns) \ ndctl_bus_foreach(ctx, bus) \ ndctl_region_foreach(bus, region) \ ndctl_namespace_foreach(region, ndns) \ /* * os_dimm_region_namespace -- (internal) returns the region * (and optionally the namespace) * where the given file is located */ static int os_dimm_region_namespace(struct ndctl_ctx *ctx, const os_stat_t *st, struct ndctl_region **pregion, struct ndctl_namespace **pndns) { LOG(3, "ctx %p stat %p pregion %p pnamespace %p", ctx, st, pregion, pndns); struct ndctl_bus *bus; struct ndctl_region *region; struct ndctl_namespace *ndns; dev_t dev = S_ISCHR(st->st_mode) ? st->st_rdev : st->st_dev; ASSERTne(pregion, NULL); *pregion = NULL; if (pndns) *pndns = NULL; FOREACH_BUS_REGION_NAMESPACE(ctx, bus, region, ndns) { struct ndctl_btt *btt; struct ndctl_dax *dax = NULL; struct ndctl_pfn *pfn; const char *devname; if ((btt = ndctl_namespace_get_btt(ndns))) { devname = ndctl_btt_get_block_device(btt); } else if ((pfn = ndctl_namespace_get_pfn(ndns))) { devname = ndctl_pfn_get_block_device(pfn); } else if ((dax = ndctl_namespace_get_dax(ndns))) { struct daxctl_region *dax_region; dax_region = ndctl_dax_get_daxctl_region(dax); /* there is always one dax device in dax_region */ if (dax_region) { struct daxctl_dev *dev; dev = daxctl_dev_get_first(dax_region); devname = daxctl_dev_get_devname(dev); } else { ERR("cannot find dax region"); return -1; } } else { devname = ndctl_namespace_get_block_device(ndns); } if (*devname == '\0') continue; char path[PATH_MAX]; os_stat_t stat; if (sprintf(path, "/dev/%s", devname) == -1) { ERR("sprintf() failed"); return -1; } if (os_stat(path, &stat)) { ERR("!stat %s", path); return -1; } if (dev == stat.st_rdev) { LOG(4, "found matching device: %s", path); *pregion = region; if (pndns) *pndns = ndns; return 0; } LOG(10, "skipping not matching device: %s", path); } LOG(10, "did not found any matching device"); return 0; } /* * os_dimm_interleave_set -- (internal) returns set of dimms * where the pool file is located */ static struct ndctl_interleave_set * os_dimm_interleave_set(struct ndctl_ctx *ctx, const os_stat_t *st) { LOG(3, "ctx %p stat %p", ctx, st); struct ndctl_region *region = NULL; if (os_dimm_region_namespace(ctx, st, ®ion, NULL)) return NULL; return region ? ndctl_region_get_interleave_set(region) : NULL; } /* * os_dimm_uid -- returns a file uid based on dimms uids * * if uid == null then function will return required buffer size */ int os_dimm_uid(const char *path, char *uid, size_t *buff_len) { LOG(3, "path %s, uid %p, len %lu", path, uid, *buff_len); os_stat_t st; struct ndctl_ctx *ctx; struct ndctl_interleave_set *set; struct ndctl_dimm *dimm; int ret = 0; if (os_stat(path, &st)) { ERR("!stat %s", path); return -1; } if (ndctl_new(&ctx)) { ERR("!ndctl_new"); return -1; } if (uid == NULL) { *buff_len = 1; /* '\0' */ } set = os_dimm_interleave_set(ctx, &st); if (set == NULL) goto end; if (uid == NULL) { ndctl_dimm_foreach_in_interleave_set(set, dimm) { *buff_len += strlen(ndctl_dimm_get_unique_id(dimm)); } goto end; } size_t len = 1; ndctl_dimm_foreach_in_interleave_set(set, dimm) { const char *dimm_uid = ndctl_dimm_get_unique_id(dimm); len += strlen(dimm_uid); if (len > *buff_len) { ret = -1; goto end; } strncat(uid, dimm_uid, *buff_len); } end: ndctl_unref(ctx); return ret; } /* * os_dimm_usc -- returns unsafe shutdown count */ int os_dimm_usc(const char *path, uint64_t *usc) { LOG(3, "path %s, uid %p", path, usc); os_stat_t st; struct ndctl_ctx *ctx; *usc = 0; if (os_stat(path, &st)) { ERR("!stat %s", path); return -1; } if (ndctl_new(&ctx)) { ERR("!ndctl_new"); return -1; } struct ndctl_interleave_set *iset = os_dimm_interleave_set(ctx, &st); if (iset == NULL) goto out; struct ndctl_dimm *dimm; ndctl_dimm_foreach_in_interleave_set(iset, dimm) { struct ndctl_cmd *cmd = ndctl_dimm_cmd_new_smart(dimm); if (ndctl_cmd_submit(cmd)) goto out; if (!(ndctl_cmd_smart_get_flags(cmd) & USC_VALID_FLAG)) goto out; *usc += ndctl_cmd_smart_get_shutdown_count(cmd); } out: ndctl_unref(ctx); return 0; } /* * os_dimm_get_namespace_bounds -- (internal) returns the bounds * (offset and size) of the given namespace * relative to the beginning of its region */ static int os_dimm_get_namespace_bounds(struct ndctl_region *region, struct ndctl_namespace *ndns, unsigned long long *ns_offset, unsigned long long *ns_size) { LOG(3, "region %p namespace %p ns_offset %p ns_size %p", region, ndns, ns_offset, ns_size); struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns); struct ndctl_dax *dax = ndctl_namespace_get_dax(ndns); ASSERTne(ns_offset, NULL); ASSERTne(ns_size, NULL); if (pfn) { *ns_offset = ndctl_pfn_get_resource(pfn); *ns_size = ndctl_pfn_get_size(pfn); } else if (dax) { *ns_offset = ndctl_dax_get_resource(dax); *ns_size = ndctl_dax_get_size(dax); } else { /* raw or btt */ *ns_offset = ndctl_namespace_get_resource(ndns); *ns_size = ndctl_namespace_get_size(ndns); } *ns_offset -= ndctl_region_get_resource(region); return 0; } /* * os_dimm_namespace_get_badblocks -- (internal) returns bad blocks * in the given namespace */ static int os_dimm_namespace_get_badblocks(struct ndctl_region *region, struct ndctl_namespace *ndns, struct badblocks *bbs) { LOG(3, "region %p, namespace %p", region, ndns); ASSERTne(bbs, NULL); unsigned long long ns_beg, ns_size, ns_end; unsigned long long bb_beg, bb_end; unsigned long long beg, end; struct bad_block *bbvp = NULL; struct bad_block *newbbvp; unsigned bb_count = 0; bbs->ns_resource = 0; bbs->bb_cnt = 0; bbs->bbv = NULL; if (os_dimm_get_namespace_bounds(region, ndns, &ns_beg, &ns_size)) { ERR("getting namespace bounds failed"); return -1; } ns_end = ns_beg + ns_size - 1; LOG(10, "namespace: begin %llu, end %llu size %llu (in 512B sectors)", B2SEC(ns_beg), B2SEC(ns_end + 1) - 1, B2SEC(ns_size)); struct badblock *bb; ndctl_region_badblock_foreach(region, bb) { bb_beg = SEC2B(bb->offset); bb_end = bb_beg + SEC2B(bb->len) - 1; LOG(10, "region bad block: begin %llu end %llu length %u (in 512B sectors)", bb->offset, bb->offset + bb->len - 1, bb->len); if (bb_beg > ns_end || ns_beg > bb_end) continue; beg = (bb_beg > ns_beg) ? bb_beg : ns_beg; end = (bb_end < ns_end) ? bb_end : ns_end; newbbvp = Realloc(bbvp, (++bb_count) * sizeof(struct bad_block)); if (newbbvp == NULL) { ERR("out of memory"); if (bbvp) Free(bbvp); return -1; } bbvp = newbbvp; bbvp[bb_count - 1].offset = beg - ns_beg; bbvp[bb_count - 1].length = (unsigned)(end - beg + 1); LOG(4, "namespace bad block: begin %llu end %llu length %llu (in 512B sectors)", B2SEC(beg - ns_beg), B2SEC(end - ns_beg), B2SEC(end - beg) + 1); } LOG(4, "number of bad blocks detected: %u", bb_count); bbs->bb_cnt = bb_count; bbs->bbv = bbvp; bbs->ns_resource = ns_beg + ndctl_region_get_resource(region); return 0; } /* * os_dimm_files_namespace_badblocks_bus -- (internal) returns badblocks * in the namespace where the given * file is located * (optionally returns also the bus) */ static int os_dimm_files_namespace_badblocks_bus(struct ndctl_ctx *ctx, const char *path, struct ndctl_bus **pbus, struct badblocks *bbs) { LOG(3, "ctx %p path %s pbus %p", ctx, path, pbus); struct ndctl_region *region; struct ndctl_namespace *ndns; os_stat_t st; if (os_stat(path, &st)) { ERR("!stat %s", path); return -1; } int rv = os_dimm_region_namespace(ctx, &st, ®ion, &ndns); if (rv) { ERR("getting region and namespace failed"); return -1; } if (region == NULL || ndns == NULL) return 0; if (pbus) *pbus = ndctl_region_get_bus(region); return os_dimm_namespace_get_badblocks(region, ndns, bbs); } /* * os_dimm_files_namespace_badblocks -- returns badblocks in the namespace * where the given file is located */ int os_dimm_files_namespace_badblocks(const char *path, struct badblocks *bbs) { LOG(3, "path %s", path); struct ndctl_ctx *ctx; if (ndctl_new(&ctx)) { ERR("!ndctl_new"); return -1; } int ret = os_dimm_files_namespace_badblocks_bus(ctx, path, NULL, bbs); ndctl_unref(ctx); return ret; } /* * os_dimm_devdax_clear_one_badblock -- (internal) clear one bad block * in the dax device */ static int os_dimm_devdax_clear_one_badblock(struct ndctl_bus *bus, unsigned long long address, unsigned long long length) { LOG(3, "bus %p address 0x%llx length %llu (bytes)", bus, address, length); int ret = 0; struct ndctl_cmd *cmd_ars_cap = ndctl_bus_cmd_new_ars_cap(bus, address, length); if (cmd_ars_cap == NULL) { ERR("failed to create cmd (bus '%s')", ndctl_bus_get_provider(bus)); return -1; } if ((ret = ndctl_cmd_submit(cmd_ars_cap)) < 0) { ERR("failed to submit cmd (bus '%s')", ndctl_bus_get_provider(bus)); goto out_ars_cap; } struct ndctl_cmd *cmd_ars_start = ndctl_bus_cmd_new_ars_start(cmd_ars_cap, ND_ARS_PERSISTENT); if (cmd_ars_start == NULL) { ERR("ndctl_bus_cmd_new_ars_start() failed"); goto out_ars_cap; } if ((ret = ndctl_cmd_submit(cmd_ars_start)) < 0) { ERR("failed to submit cmd (bus '%s')", ndctl_bus_get_provider(bus)); goto out_ars_start; } struct ndctl_cmd *cmd_ars_status; do { cmd_ars_status = ndctl_bus_cmd_new_ars_status(cmd_ars_cap); if (cmd_ars_status == NULL) { ERR("ndctl_bus_cmd_new_ars_status() failed"); goto out_ars_start; } if ((ret = ndctl_cmd_submit(cmd_ars_status)) < 0) { ERR("failed to submit cmd (bus '%s')", ndctl_bus_get_provider(bus)); goto out_ars_status; } } while (ndctl_cmd_ars_in_progress(cmd_ars_status)); struct ndctl_range range; ndctl_cmd_ars_cap_get_range(cmd_ars_cap, &range); struct ndctl_cmd *cmd_clear_error = ndctl_bus_cmd_new_clear_error( range.address, range.length, cmd_ars_cap); if ((ret = ndctl_cmd_submit(cmd_clear_error)) < 0) { ERR("failed to submit cmd (bus '%s')", ndctl_bus_get_provider(bus)); goto out_clear_error; } size_t cleared = ndctl_cmd_clear_error_get_cleared(cmd_clear_error); LOG(4, "cleared %zu out of %llu bad blocks", cleared, length); ret = cleared == length ? 0 : -1; out_clear_error: ndctl_cmd_unref(cmd_clear_error); out_ars_status: ndctl_cmd_unref(cmd_ars_status); out_ars_start: ndctl_cmd_unref(cmd_ars_start); out_ars_cap: ndctl_cmd_unref(cmd_ars_cap); return ret; } /* * os_dimm_devdax_clear_badblocks -- clear all bad blocks in the dax device */ int os_dimm_devdax_clear_badblocks(const char *path) { LOG(3, "path %s", path); struct ndctl_ctx *ctx; struct ndctl_bus *bus; struct badblocks *bbs; int ret; if (ndctl_new(&ctx)) { ERR("!ndctl_new"); return -1; } bbs = Zalloc(sizeof(struct badblocks)); if (bbs == NULL) { ERR("out of memory"); return -1; } ret = os_dimm_files_namespace_badblocks_bus(ctx, path, &bus, bbs); if (ret) { ERR("getting bad blocks for the file failed -- %s", path); goto exit_free_all; } if (bbs->bb_cnt == 0 || bbs->bbv == NULL) /* OK - no bad blocks found */ goto exit_free_all; LOG(4, "clearing %u bad block(s)...", bbs->bb_cnt); unsigned b; for (b = 0; b < bbs->bb_cnt; b++) { LOG(4, "clearing bad block: offset %llu length %u (in 512B sectors)", B2SEC(bbs->bbv[b].offset), B2SEC(bbs->bbv[b].length)); ret = os_dimm_devdax_clear_one_badblock(bus, bbs->bbv[b].offset + bbs->ns_resource, bbs->bbv[b].length); if (ret) { ERR( "failed to clear bad block: offset %llu length %u (in 512B sectors)", B2SEC(bbs->bbv[b].offset), B2SEC(bbs->bbv[b].length)); } } exit_free_all: if (bbs && bbs->bbv) Free(bbs->bbv); if (bbs) Free(bbs); ndctl_unref(ctx); return ret; } pmdk-1.4.1/src/common/os_dimm_none.c000066400000000000000000000050141331545616200173470ustar00rootroot00000000000000/* * Copyright 2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_dimm_none.c -- fake dimm functions */ #include "out.h" #include "os.h" #include "os_dimm.h" /* * os_dimm_uid -- returns empty uid */ int os_dimm_uid(const char *path, char *uid, size_t *len) { LOG(3, "path %s, uid %p, len %lu", path, uid, *len); if (uid == NULL) { *len = 1; } else { *uid = '\0'; } return 0; } /* * os_dimm_usc -- returns fake unsafe shutdown count */ int os_dimm_usc(const char *path, uint64_t *usc) { LOG(3, "path %s, usc %p", path, usc); *usc = 0; return 0; } /* * os_dimm_files_namespace_badblocks -- fake os_dimm_files_namespace_badblocks() */ int os_dimm_files_namespace_badblocks(const char *path, struct badblocks *bbs) { LOG(3, "path %s", path); os_stat_t st; if (os_stat(path, &st)) { ERR("!stat %s", path); return -1; } return 0; } /* * os_dimm_devdax_clear_badblocks -- fake bad block clearing routine */ int os_dimm_devdax_clear_badblocks(const char *path) { LOG(3, "path %s", path); return 0; } pmdk-1.4.1/src/common/os_posix.c000066400000000000000000000145011331545616200165450ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_posix.c -- abstraction layer for basic Posix functions */ #define _GNU_SOURCE #include #include #include #ifdef __FreeBSD__ #include #endif #include #include #include #include #include #include #include #include #include "util.h" #include "out.h" #include "os.h" /* * os_open -- open abstraction layer */ int os_open(const char *pathname, int flags, ...) { int mode_required = (flags & O_CREAT) == O_CREAT; #ifdef O_TMPFILE mode_required |= (flags & O_TMPFILE) == O_TMPFILE; #endif if (mode_required) { va_list arg; va_start(arg, flags); /* Clang requires int due to auto-promotion */ int mode = va_arg(arg, int); va_end(arg); return open(pathname, flags, (mode_t)mode); } else { return open(pathname, flags); } } /* * os_stat -- stat abstraction layer */ int os_stat(const char *pathname, os_stat_t *buf) { return stat(pathname, buf); } /* * os_unlink -- unlink abstraction layer */ int os_unlink(const char *pathname) { return unlink(pathname); } /* * os_access -- access abstraction layer */ int os_access(const char *pathname, int mode) { return access(pathname, mode); } /* * os_fopen -- fopen abstraction layer */ FILE * os_fopen(const char *pathname, const char *mode) { return fopen(pathname, mode); } /* * os_fdopen -- fdopen abstraction layer */ FILE * os_fdopen(int fd, const char *mode) { return fdopen(fd, mode); } /* * os_chmod -- chmod abstraction layer */ int os_chmod(const char *pathname, mode_t mode) { return chmod(pathname, mode); } /* * os_mkstemp -- mkstemp abstraction layer */ int os_mkstemp(char *temp) { return mkstemp(temp); } /* * os_posix_fallocate -- posix_fallocate abstraction layer */ int os_posix_fallocate(int fd, os_off_t offset, off_t len) { #ifdef __FreeBSD__ struct stat fbuf; struct statfs fsbuf; /* * XXX Workaround for https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=223287 * * FreeBSD implements posix_fallocate with a simple block allocation/zero * loop. If the requested size is unreasonably large, this can result in * an uninterruptable system call that will suck up all the space in the * file system and could take hours to fail. To avoid this, make a crude * check to see if the requested allocation is larger than the available * space in the file system (minus any blocks already allocated to the * file), and if so, immediately return ENOSPC. We do the check only if * the offset is 0; otherwise, trying to figure out how many additional * blocks are required is too complicated. * * This workaround is here mostly to fail "absurdly" large requests for * testing purposes; however, it is coded to allow normal (albeit slow) * operation if the space can actually be allocated. Because of the way * PMDK uses posix_fallocate, supporting Linux-style fallocate in * FreeBSD should be considered. */ if (offset == 0) { if (fstatfs(fd, &fsbuf) == -1 || fstat(fd, &fbuf) == -1) return errno; size_t reqd_blocks = (((size_t)len + (fsbuf.f_bsize - 1)) / fsbuf.f_bsize) - (size_t)fbuf.st_blocks; if (reqd_blocks > (size_t)fsbuf.f_bavail) return ENOSPC; } #endif return posix_fallocate(fd, offset, len); } /* * os_ftruncate -- ftruncate abstraction layer */ int os_ftruncate(int fd, os_off_t length) { return ftruncate(fd, length); } /* * os_flock -- flock abstraction layer */ int os_flock(int fd, int operation) { int opt = 0; if (operation & OS_LOCK_EX) opt |= LOCK_EX; if (operation & OS_LOCK_SH) opt |= LOCK_SH; if (operation & OS_LOCK_UN) opt |= LOCK_UN; if (operation & OS_LOCK_NB) opt |= LOCK_NB; return flock(fd, opt); } /* * os_writev -- writev abstraction layer */ ssize_t os_writev(int fd, const struct iovec *iov, int iovcnt) { return writev(fd, iov, iovcnt); } /* * os_clock_gettime -- clock_gettime abstraction layer */ int os_clock_gettime(int id, struct timespec *ts) { return clock_gettime(id, ts); } /* * os_rand_r -- rand_r abstraction layer */ int os_rand_r(unsigned *seedp) { return rand_r(seedp); } /* * os_unsetenv -- unsetenv abstraction layer */ int os_unsetenv(const char *name) { return unsetenv(name); } /* * os_setenv -- setenv abstraction layer */ int os_setenv(const char *name, const char *value, int overwrite) { return setenv(name, value, overwrite); } /* * secure_getenv -- provide GNU secure_getenv for FreeBSD */ #ifdef __FreeBSD__ static char * secure_getenv(const char *name) { if (issetugid() != 0) return NULL; return getenv(name); } #endif /* * os_getenv -- getenv abstraction layer */ char * os_getenv(const char *name) { return secure_getenv(name); } /* * os_strsignal -- strsignal abstraction layer */ const char *os_strsignal(int sig) { return strsignal(sig); } pmdk-1.4.1/src/common/os_thread.h000066400000000000000000000133111331545616200166550ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_thread.h -- os thread abstraction layer */ #ifndef OS_THREAD_H #define OS_THREAD_H 1 #ifdef __cplusplus extern "C" { #endif #include #include typedef union { long long align; char padding[44]; /* linux: 40 windows: 44 */ } os_mutex_t; typedef union { long long align; char padding[56]; /* linux: 56 windows: 13 */ } os_rwlock_t; typedef union { long long align; char padding[48]; /* linux: 48 windows: 12 */ } os_cond_t; typedef union { long long align; char padding[32]; /* linux: 8 windows: 32 */ } os_thread_t; typedef union { long long align; /* linux: long windows: 8 FreeBSD: 12 */ char padding[16]; /* 16 to be safe */ } os_once_t; #define OS_ONCE_INIT { .padding = {0} } typedef unsigned os_tls_key_t; typedef union { long long align; char padding[56]; /* linux: 56 windows: 8 */ } os_semaphore_t; typedef union { long long align; char padding[56]; /* linux: 56 windows: 8 */ } os_thread_attr_t; typedef union { long long align; char padding[512]; } os_cpu_set_t; #ifdef __FreeBSD__ #define cpu_set_t cpuset_t typedef uintptr_t os_spinlock_t; #else typedef volatile int os_spinlock_t; /* XXX: not implemented on windows */ #endif void os_cpu_zero(os_cpu_set_t *set); void os_cpu_set(size_t cpu, os_cpu_set_t *set); #ifndef _WIN32 #define _When_(...) #endif int os_once(os_once_t *o, void (*func)(void)); int os_tls_key_create(os_tls_key_t *key, void (*destructor)(void *)); int os_tls_key_delete(os_tls_key_t key); int os_tls_set(os_tls_key_t key, const void *value); void *os_tls_get(os_tls_key_t key); int os_mutex_init(os_mutex_t *__restrict mutex); int os_mutex_destroy(os_mutex_t *__restrict mutex); _When_(return == 0, _Acquires_lock_(mutex->lock)) int os_mutex_lock(os_mutex_t *__restrict mutex); _When_(return == 0, _Acquires_lock_(mutex->lock)) int os_mutex_trylock(os_mutex_t *__restrict mutex); int os_mutex_unlock(os_mutex_t *__restrict mutex); /* XXX - non POSIX */ int os_mutex_timedlock(os_mutex_t *__restrict mutex, const struct timespec *abstime); int os_rwlock_init(os_rwlock_t *__restrict rwlock); int os_rwlock_destroy(os_rwlock_t *__restrict rwlock); int os_rwlock_rdlock(os_rwlock_t *__restrict rwlock); int os_rwlock_wrlock(os_rwlock_t *__restrict rwlock); int os_rwlock_tryrdlock(os_rwlock_t *__restrict rwlock); _When_(return == 0, _Acquires_exclusive_lock_(rwlock->lock)) int os_rwlock_trywrlock(os_rwlock_t *__restrict rwlock); _When_(rwlock->is_write != 0, _Requires_exclusive_lock_held_(rwlock->lock)) _When_(rwlock->is_write == 0, _Requires_shared_lock_held_(rwlock->lock)) int os_rwlock_unlock(os_rwlock_t *__restrict rwlock); int os_rwlock_timedrdlock(os_rwlock_t *__restrict rwlock, const struct timespec *abstime); int os_rwlock_timedwrlock(os_rwlock_t *__restrict rwlock, const struct timespec *abstime); int os_spin_init(os_spinlock_t *lock, int pshared); int os_spin_destroy(os_spinlock_t *lock); int os_spin_lock(os_spinlock_t *lock); int os_spin_unlock(os_spinlock_t *lock); int os_spin_trylock(os_spinlock_t *lock); int os_cond_init(os_cond_t *__restrict cond); int os_cond_destroy(os_cond_t *__restrict cond); int os_cond_broadcast(os_cond_t *__restrict cond); int os_cond_signal(os_cond_t *__restrict cond); int os_cond_timedwait(os_cond_t *__restrict cond, os_mutex_t *__restrict mutex, const struct timespec *abstime); int os_cond_wait(os_cond_t *__restrict cond, os_mutex_t *__restrict mutex); /* threading */ int os_thread_create(os_thread_t *thread, const os_thread_attr_t *attr, void *(*start_routine)(void *), void *arg); int os_thread_join(os_thread_t *thread, void **result); void os_thread_self(os_thread_t *thread); /* thread affinity */ int os_thread_setaffinity_np(os_thread_t *thread, size_t set_size, const os_cpu_set_t *set); int os_thread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); int os_semaphore_init(os_semaphore_t *sem, unsigned value); int os_semaphore_destroy(os_semaphore_t *sem); int os_semaphore_wait(os_semaphore_t *sem); int os_semaphore_trywait(os_semaphore_t *sem); int os_semaphore_post(os_semaphore_t *sem); #ifdef __cplusplus } #endif #endif /* OS_THREAD_H */ pmdk-1.4.1/src/common/os_thread_posix.c000066400000000000000000000247211331545616200201010ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_thread_posix.c -- Posix thread abstraction layer */ #define _GNU_SOURCE #include #ifdef __FreeBSD__ #include #endif #include #include "os_thread.h" #include "util.h" typedef struct { pthread_t thread; } internal_os_thread_t; /* * os_once -- pthread_once abstraction layer */ int os_once(os_once_t *o, void (*func)(void)) { COMPILE_ERROR_ON(sizeof(os_once_t) < sizeof(pthread_once_t)); return pthread_once((pthread_once_t *)o, func); } /* * os_tls_key_create -- pthread_key_create abstraction layer */ int os_tls_key_create(os_tls_key_t *key, void (*destructor)(void *)) { COMPILE_ERROR_ON(sizeof(os_tls_key_t) < sizeof(pthread_key_t)); return pthread_key_create((pthread_key_t *)key, destructor); } /* * os_tls_key_delete -- pthread_key_delete abstraction layer */ int os_tls_key_delete(os_tls_key_t key) { return pthread_key_delete((pthread_key_t)key); } /* * os_tls_setspecific -- pthread_key_setspecific abstraction layer */ int os_tls_set(os_tls_key_t key, const void *value) { return pthread_setspecific((pthread_key_t)key, value); } /* * os_tls_get -- pthread_key_getspecific abstraction layer */ void * os_tls_get(os_tls_key_t key) { return pthread_getspecific((pthread_key_t)key); } /* * os_mutex_init -- pthread_mutex_init abstraction layer */ int os_mutex_init(os_mutex_t *__restrict mutex) { COMPILE_ERROR_ON(sizeof(os_mutex_t) < sizeof(pthread_mutex_t)); return pthread_mutex_init((pthread_mutex_t *)mutex, NULL); } /* * os_mutex_destroy -- pthread_mutex_destroy abstraction layer */ int os_mutex_destroy(os_mutex_t *__restrict mutex) { return pthread_mutex_destroy((pthread_mutex_t *)mutex); } /* * os_mutex_lock -- pthread_mutex_lock abstraction layer */ int os_mutex_lock(os_mutex_t *__restrict mutex) { return pthread_mutex_lock((pthread_mutex_t *)mutex); } /* * os_mutex_trylock -- pthread_mutex_trylock abstraction layer */ int os_mutex_trylock(os_mutex_t *__restrict mutex) { return pthread_mutex_trylock((pthread_mutex_t *)mutex); } /* * os_mutex_unlock -- pthread_mutex_unlock abstraction layer */ int os_mutex_unlock(os_mutex_t *__restrict mutex) { return pthread_mutex_unlock((pthread_mutex_t *)mutex); } /* * os_mutex_timedlock -- pthread_mutex_timedlock abstraction layer */ int os_mutex_timedlock(os_mutex_t *__restrict mutex, const struct timespec *abstime) { return pthread_mutex_timedlock((pthread_mutex_t *)mutex, abstime); } /* * os_rwlock_init -- pthread_rwlock_init abstraction layer */ int os_rwlock_init(os_rwlock_t *__restrict rwlock) { COMPILE_ERROR_ON(sizeof(os_rwlock_t) < sizeof(pthread_rwlock_t)); return pthread_rwlock_init((pthread_rwlock_t *)rwlock, NULL); } /* * os_rwlock_destroy -- pthread_rwlock_destroy abstraction layer */ int os_rwlock_destroy(os_rwlock_t *__restrict rwlock) { return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock); } /* * os_rwlock_rdlock - pthread_rwlock_rdlock abstraction layer */ int os_rwlock_rdlock(os_rwlock_t *__restrict rwlock) { return pthread_rwlock_rdlock((pthread_rwlock_t *)rwlock); } /* * os_rwlock_wrlock -- pthread_rwlock_wrlock abstraction layer */ int os_rwlock_wrlock(os_rwlock_t *__restrict rwlock) { return pthread_rwlock_wrlock((pthread_rwlock_t *)rwlock); } /* * os_rwlock_unlock -- pthread_rwlock_unlock abstraction layer */ int os_rwlock_unlock(os_rwlock_t *__restrict rwlock) { return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock); } /* * os_rwlock_tryrdlock -- pthread_rwlock_tryrdlock abstraction layer */ int os_rwlock_tryrdlock(os_rwlock_t *__restrict rwlock) { return pthread_rwlock_tryrdlock((pthread_rwlock_t *)rwlock); } /* * os_rwlock_tryrwlock -- pthread_rwlock_trywrlock abstraction layer */ int os_rwlock_trywrlock(os_rwlock_t *__restrict rwlock) { return pthread_rwlock_trywrlock((pthread_rwlock_t *)rwlock); } /* * os_rwlock_timedrdlock -- pthread_rwlock_timedrdlock abstraction layer */ int os_rwlock_timedrdlock(os_rwlock_t *__restrict rwlock, const struct timespec *abstime) { return pthread_rwlock_timedrdlock((pthread_rwlock_t *)rwlock, abstime); } /* * os_rwlock_timedwrlock -- pthread_rwlock_timedwrlock abstraction layer */ int os_rwlock_timedwrlock(os_rwlock_t *__restrict rwlock, const struct timespec *abstime) { return pthread_rwlock_timedwrlock((pthread_rwlock_t *)rwlock, abstime); } /* * os_spin_init -- pthread_spin_init abstraction layer */ int os_spin_init(os_spinlock_t *lock, int pshared) { COMPILE_ERROR_ON(sizeof(os_spinlock_t) < sizeof(pthread_spinlock_t)); return pthread_spin_init((pthread_spinlock_t *)lock, pshared); } /* * os_spin_destroy -- pthread_spin_destroy abstraction layer */ int os_spin_destroy(os_spinlock_t *lock) { return pthread_spin_destroy((pthread_spinlock_t *)lock); } /* * os_spin_lock -- pthread_spin_lock abstraction layer */ int os_spin_lock(os_spinlock_t *lock) { return pthread_spin_lock((pthread_spinlock_t *)lock); } /* * os_spin_unlock -- pthread_spin_unlock abstraction layer */ int os_spin_unlock(os_spinlock_t *lock) { return pthread_spin_unlock((pthread_spinlock_t *)lock); } /* * os_spin_trylock -- pthread_spin_trylock abstraction layer */ int os_spin_trylock(os_spinlock_t *lock) { return pthread_spin_trylock((pthread_spinlock_t *)lock); } /* * os_cond_init -- pthread_cond_init abstraction layer */ int os_cond_init(os_cond_t *__restrict cond) { COMPILE_ERROR_ON(sizeof(os_cond_t) < sizeof(pthread_cond_t)); return pthread_cond_init((pthread_cond_t *)cond, NULL); } /* * os_cond_destroy -- pthread_cond_destroy abstraction layer */ int os_cond_destroy(os_cond_t *__restrict cond) { return pthread_cond_destroy((pthread_cond_t *)cond); } /* * os_cond_broadcast -- pthread_cond_broadcast abstraction layer */ int os_cond_broadcast(os_cond_t *__restrict cond) { return pthread_cond_broadcast((pthread_cond_t *)cond); } /* * os_cond_signal -- pthread_cond_signal abstraction layer */ int os_cond_signal(os_cond_t *__restrict cond) { return pthread_cond_signal((pthread_cond_t *)cond); } /* * os_cond_timedwait -- pthread_cond_timedwait abstraction layer */ int os_cond_timedwait(os_cond_t *__restrict cond, os_mutex_t *__restrict mutex, const struct timespec *abstime) { return pthread_cond_timedwait((pthread_cond_t *)cond, (pthread_mutex_t *)mutex, abstime); } /* * os_cond_wait -- pthread_cond_wait abstraction layer */ int os_cond_wait(os_cond_t *__restrict cond, os_mutex_t *__restrict mutex) { return pthread_cond_wait((pthread_cond_t *)cond, (pthread_mutex_t *)mutex); } /* * os_thread_create -- pthread_create abstraction layer */ int os_thread_create(os_thread_t *thread, const os_thread_attr_t *attr, void *(*start_routine)(void *), void *arg) { COMPILE_ERROR_ON(sizeof(os_thread_t) < sizeof(internal_os_thread_t)); internal_os_thread_t *thread_info = (internal_os_thread_t *)thread; return pthread_create(&thread_info->thread, (pthread_attr_t *)attr, start_routine, arg); } /* * os_thread_join -- pthread_join abstraction layer */ int os_thread_join(os_thread_t *thread, void **result) { internal_os_thread_t *thread_info = (internal_os_thread_t *)thread; return pthread_join(thread_info->thread, result); } /* * os_thread_self -- pthread_self abstraction layer */ void os_thread_self(os_thread_t *thread) { internal_os_thread_t *thread_info = (internal_os_thread_t *)thread; thread_info->thread = pthread_self(); } /* * os_thread_atfork -- pthread_atfork abstraction layer */ int os_thread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { return pthread_atfork(prepare, parent, child); } /* * os_thread_setaffinity_np -- pthread_atfork abstraction layer */ int os_thread_setaffinity_np(os_thread_t *thread, size_t set_size, const os_cpu_set_t *set) { COMPILE_ERROR_ON(sizeof(os_cpu_set_t) < sizeof(cpu_set_t)); internal_os_thread_t *thread_info = (internal_os_thread_t *)thread; return pthread_setaffinity_np(thread_info->thread, set_size, (cpu_set_t *)set); } /* * os_cpu_zero -- CP_ZERO abstraction layer */ void os_cpu_zero(os_cpu_set_t *set) { CPU_ZERO((cpu_set_t *)set); } /* * os_cpu_set -- CP_SET abstraction layer */ void os_cpu_set(size_t cpu, os_cpu_set_t *set) { CPU_SET(cpu, (cpu_set_t *)set); } /* * os_semaphore_init -- initializes semaphore instance */ int os_semaphore_init(os_semaphore_t *sem, unsigned value) { COMPILE_ERROR_ON(sizeof(os_semaphore_t) < sizeof(sem_t)); return sem_init((sem_t *)sem, 0, value); } /* * os_semaphore_destroy -- destroys a semaphore instance */ int os_semaphore_destroy(os_semaphore_t *sem) { return sem_destroy((sem_t *)sem); } /* * os_semaphore_wait -- decreases the value of the semaphore */ int os_semaphore_wait(os_semaphore_t *sem) { return sem_wait((sem_t *)sem); } /* * os_semaphore_trywait -- tries to decrease the value of the semaphore */ int os_semaphore_trywait(os_semaphore_t *sem) { return sem_trywait((sem_t *)sem); } /* * os_semaphore_post -- increases the value of the semaphore */ int os_semaphore_post(os_semaphore_t *sem) { return sem_post((sem_t *)sem); } pmdk-1.4.1/src/common/os_thread_windows.c000066400000000000000000000360241331545616200204300ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_thread_windows.c -- (imperfect) POSIX-like threads for Windows * * Loosely inspired by: * http://locklessinc.com/articles/pthreads_on_windows/ */ #include #include #include #include #include "os_thread.h" #include "util.h" #include "out.h" typedef struct { unsigned attr; CRITICAL_SECTION lock; } internal_os_mutex_t; typedef struct { unsigned attr; char is_write; SRWLOCK lock; } internal_os_rwlock_t; typedef struct { unsigned attr; CONDITION_VARIABLE cond; } internal_os_cond_t; typedef long long internal_os_once_t; typedef struct { HANDLE handle; } internal_semaphore_t; typedef struct { GROUP_AFFINITY affinity; } internal_os_cpu_set_t; typedef struct { HANDLE thread_handle; void *arg; void *(*start_routine)(void *); void *result; } internal_os_thread_t; /* number of useconds between 1970-01-01T00:00:00Z and 1601-01-01T00:00:00Z */ #define DELTA_WIN2UNIX (11644473600000000ull) #define TIMED_LOCK(action, ts) {\ if ((action) == TRUE)\ return 0;\ unsigned long long et = (ts)->tv_sec * 1000000000 + (ts)->tv_nsec;\ while (1) {\ FILETIME _t;\ GetSystemTimeAsFileTime(&_t);\ ULARGE_INTEGER _UI = {\ .HighPart = _t.dwHighDateTime,\ .LowPart = _t.dwLowDateTime,\ };\ if (100 * _UI.QuadPart - 1000 * DELTA_WIN2UNIX >= et)\ return ETIMEDOUT;\ if ((action) == TRUE)\ return 0;\ Sleep(1);\ }\ return ETIMEDOUT;\ } /* * os_mutex_init -- initializes mutex */ int os_mutex_init(os_mutex_t *__restrict mutex) { COMPILE_ERROR_ON(sizeof(os_mutex_t) < sizeof(internal_os_mutex_t)); internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; InitializeCriticalSection(&mutex_internal->lock); return 0; } /* * os_mutex_destroy -- destroys mutex */ int os_mutex_destroy(os_mutex_t *__restrict mutex) { internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; DeleteCriticalSection(&mutex_internal->lock); return 0; } /* * os_mutex_lock -- locks mutex */ _Use_decl_annotations_ int os_mutex_lock(os_mutex_t *__restrict mutex) { internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; EnterCriticalSection(&mutex_internal->lock); if (mutex_internal->lock.RecursionCount > 1) { LeaveCriticalSection(&mutex_internal->lock); FATAL("deadlock detected"); } return 0; } /* * os_mutex_trylock -- tries lock mutex */ _Use_decl_annotations_ int os_mutex_trylock(os_mutex_t *__restrict mutex) { internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; if (TryEnterCriticalSection(&mutex_internal->lock) == FALSE) return EBUSY; if (mutex_internal->lock.RecursionCount > 1) { LeaveCriticalSection(&mutex_internal->lock); return EBUSY; } return 0; } /* * os_mutex_timedlock -- tries lock mutex with timeout */ int os_mutex_timedlock(os_mutex_t *__restrict mutex, const struct timespec *abstime) { TIMED_LOCK((os_mutex_trylock(mutex) == 0), abstime); } /* * os_mutex_unlock -- unlocks mutex */ int os_mutex_unlock(os_mutex_t *__restrict mutex) { internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; LeaveCriticalSection(&mutex_internal->lock); return 0; } /* * os_rwlock_init -- initializes rwlock */ int os_rwlock_init(os_rwlock_t *__restrict rwlock) { COMPILE_ERROR_ON(sizeof(os_rwlock_t) < sizeof(internal_os_rwlock_t)); internal_os_rwlock_t *rwlock_internal = (internal_os_rwlock_t *)rwlock; InitializeSRWLock(&rwlock_internal->lock); return 0; } /* * os_rwlock_destroy -- destroys rwlock */ int os_rwlock_destroy(os_rwlock_t *__restrict rwlock) { /* do nothing */ UNREFERENCED_PARAMETER(rwlock); return 0; } /* * os_rwlock_rdlock -- get shared lock */ int os_rwlock_rdlock(os_rwlock_t *__restrict rwlock) { internal_os_rwlock_t *rwlock_internal = (internal_os_rwlock_t *)rwlock; AcquireSRWLockShared(&rwlock_internal->lock); rwlock_internal->is_write = 0; return 0; } /* * os_rwlock_wrlock -- get exclusive lock */ int os_rwlock_wrlock(os_rwlock_t *__restrict rwlock) { internal_os_rwlock_t *rwlock_internal = (internal_os_rwlock_t *)rwlock; AcquireSRWLockExclusive(&rwlock_internal->lock); rwlock_internal->is_write = 1; return 0; } /* * os_rwlock_tryrdlock -- tries get shared lock */ int os_rwlock_tryrdlock(os_rwlock_t *__restrict rwlock) { internal_os_rwlock_t *rwlock_internal = (internal_os_rwlock_t *)rwlock; if (TryAcquireSRWLockShared(&rwlock_internal->lock) == FALSE) { return EBUSY; } else { rwlock_internal->is_write = 0; return 0; } } /* * os_rwlock_trywrlock -- tries get exclusive lock */ _Use_decl_annotations_ int os_rwlock_trywrlock(os_rwlock_t *__restrict rwlock) { internal_os_rwlock_t *rwlock_internal = (internal_os_rwlock_t *)rwlock; if (TryAcquireSRWLockExclusive(&rwlock_internal->lock) == FALSE) { return EBUSY; } else { rwlock_internal->is_write = 1; return 0; } } /* * os_rwlock_timedrdlock -- gets shared lock with timeout */ int os_rwlock_timedrdlock(os_rwlock_t *__restrict rwlock, const struct timespec *abstime) { TIMED_LOCK((os_rwlock_tryrdlock(rwlock) == 0), abstime); } /* * os_rwlock_timedwrlock -- gets exclusive lock with timeout */ int os_rwlock_timedwrlock(os_rwlock_t *__restrict rwlock, const struct timespec *abstime) { TIMED_LOCK((os_rwlock_trywrlock(rwlock) == 0), abstime); } /* * os_rwlock_unlock -- unlocks rwlock */ _Use_decl_annotations_ int os_rwlock_unlock(os_rwlock_t *__restrict rwlock) { internal_os_rwlock_t *rwlock_internal = (internal_os_rwlock_t *)rwlock; if (rwlock_internal->is_write) ReleaseSRWLockExclusive(&rwlock_internal->lock); else ReleaseSRWLockShared(&rwlock_internal->lock); return 0; } /* * os_cond_init -- initializes condition variable */ int os_cond_init(os_cond_t *__restrict cond) { COMPILE_ERROR_ON(sizeof(os_cond_t) < sizeof(internal_os_cond_t)); internal_os_cond_t *cond_internal = (internal_os_cond_t *)cond; InitializeConditionVariable(&cond_internal->cond); return 0; } /* * os_cond_destroy -- destroys condition variable */ int os_cond_destroy(os_cond_t *__restrict cond) { /* do nothing */ UNREFERENCED_PARAMETER(cond); return 0; } /* * os_cond_broadcast -- broadcast condition variable */ int os_cond_broadcast(os_cond_t *__restrict cond) { internal_os_cond_t *cond_internal = (internal_os_cond_t *)cond; WakeAllConditionVariable(&cond_internal->cond); return 0; } /* * os_cond_wait -- signal condition variable */ int os_cond_signal(os_cond_t *__restrict cond) { internal_os_cond_t *cond_internal = (internal_os_cond_t *)cond; WakeConditionVariable(&cond_internal->cond); return 0; } /* * get_rel_wait -- (internal) convert timespec to windows timeout */ static DWORD get_rel_wait(const struct timespec *abstime) { struct __timeb64 t; _ftime64_s(&t); time_t now_ms = t.time * 1000 + t.millitm; time_t ms = (time_t)(abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000); DWORD rel_wait = (DWORD)(ms - now_ms); return rel_wait < 0 ? 0 : rel_wait; } /* * os_cond_timedwait -- waits on condition variable with timeout */ int os_cond_timedwait(os_cond_t *__restrict cond, os_mutex_t *__restrict mutex, const struct timespec *abstime) { internal_os_cond_t *cond_internal = (internal_os_cond_t *)cond; internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; BOOL ret; SetLastError(0); ret = SleepConditionVariableCS(&cond_internal->cond, &mutex_internal->lock, get_rel_wait(abstime)); if (ret == FALSE) return (GetLastError() == ERROR_TIMEOUT) ? ETIMEDOUT : EINVAL; return 0; } /* * os_cond_wait -- waits on condition variable */ int os_cond_wait(os_cond_t *__restrict cond, os_mutex_t *__restrict mutex) { internal_os_cond_t *cond_internal = (internal_os_cond_t *)cond; internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex; /* XXX - return error code based on GetLastError() */ BOOL ret; ret = SleepConditionVariableCS(&cond_internal->cond, &mutex_internal->lock, INFINITE); return (ret == FALSE) ? EINVAL : 0; } /* * os_once -- once-only function call */ int os_once(os_once_t *once, void (*func)(void)) { internal_os_once_t *once_internal = (internal_os_once_t *)once; internal_os_once_t tmp; while ((tmp = *once_internal) != 2) { if (tmp == 1) continue; /* another thread is already calling func() */ /* try to be the first one... */ if (!util_bool_compare_and_swap64(once_internal, tmp, 1)) continue; /* sorry, another thread was faster */ func(); if (!util_bool_compare_and_swap64(once_internal, 1, 2)) { ERR("error setting once"); return -1; } } return 0; } /* * os_tls_key_create -- creates a new tls key */ int os_tls_key_create(os_tls_key_t *key, void (*destructor)(void *)) { *key = FlsAlloc(destructor); if (*key == TLS_OUT_OF_INDEXES) return EAGAIN; return 0; } /* * os_tls_key_delete -- deletes key from tls */ int os_tls_key_delete(os_tls_key_t key) { if (!FlsFree(key)) return EINVAL; return 0; } /* * os_tls_set -- sets a value in tls */ int os_tls_set(os_tls_key_t key, const void *value) { if (!FlsSetValue(key, (LPVOID)value)) return ENOENT; return 0; } /* * os_tls_get -- gets a value from tls */ void * os_tls_get(os_tls_key_t key) { return FlsGetValue(key); } /* threading */ /* * os_thread_start_routine_wrapper is a start routine for _beginthreadex() and * it helps: * * - wrap the os_thread_create's start function */ static unsigned __stdcall os_thread_start_routine_wrapper(void *arg) { internal_os_thread_t *thread_info = (internal_os_thread_t *)arg; thread_info->result = thread_info->start_routine(thread_info->arg); return 0; } /* * os_thread_create -- starts a new thread */ int os_thread_create(os_thread_t *thread, const os_thread_attr_t *attr, void *(*start_routine)(void *), void *arg) { COMPILE_ERROR_ON(sizeof(os_thread_t) < sizeof(internal_os_thread_t)); internal_os_thread_t *thread_info = (internal_os_thread_t *)thread; thread_info->start_routine = start_routine; thread_info->arg = arg; thread_info->thread_handle = (HANDLE)_beginthreadex(NULL, 0, os_thread_start_routine_wrapper, thread_info, CREATE_SUSPENDED, NULL); if (thread_info->thread_handle == 0) { free(thread_info); return errno; } if (ResumeThread(thread_info->thread_handle) == -1) { free(thread_info); return EAGAIN; } return 0; } /* * os_thread_join -- joins a thread */ int os_thread_join(os_thread_t *thread, void **result) { internal_os_thread_t *internal_thread = (internal_os_thread_t *)thread; WaitForSingleObject(internal_thread->thread_handle, INFINITE); CloseHandle(internal_thread->thread_handle); if (result != NULL) *result = internal_thread->result; return 0; } /* * os_thread_self -- returns handle to calling thread */ void os_thread_self(os_thread_t *thread) { internal_os_thread_t *internal_thread = (internal_os_thread_t *)thread; internal_thread->thread_handle = GetCurrentThread(); } /* * os_cpu_zero -- clears cpu set */ void os_cpu_zero(os_cpu_set_t *set) { internal_os_cpu_set_t *internal_set = (internal_os_cpu_set_t *)set; memset(&internal_set->affinity, 0, sizeof(internal_set->affinity)); } /* * os_cpu_set -- adds cpu to set */ void os_cpu_set(size_t cpu, os_cpu_set_t *set) { internal_os_cpu_set_t *internal_set = (internal_os_cpu_set_t *)set; int sum = 0; int group_max = GetActiveProcessorGroupCount(); int group = 0; while (group < group_max) { sum += GetActiveProcessorCount(group); if (sum > cpu) { /* * XXX: can't set affinity to two diffrent cpu groups */ if (internal_set->affinity.Group != group) { internal_set->affinity.Mask = 0; internal_set->affinity.Group = group; } cpu -= sum - GetActiveProcessorCount(group); internal_set->affinity.Mask |= 1LL << cpu; return; } group++; } FATAL("os_cpu_set cpu out of bounds"); } /* * os_thread_setaffinity_np -- sets affinity of the thread */ int os_thread_setaffinity_np(os_thread_t *thread, size_t set_size, const os_cpu_set_t *set) { internal_os_cpu_set_t *internal_set = (internal_os_cpu_set_t *)set; internal_os_thread_t *internal_thread = (internal_os_thread_t *)thread; int ret = SetThreadGroupAffinity(internal_thread->thread_handle, &internal_set->affinity, NULL); return ret != 0 ? 0 : EINVAL; } /* * os_semaphore_init -- initializes a new semaphore instance */ int os_semaphore_init(os_semaphore_t *sem, unsigned value) { internal_semaphore_t *internal_sem = (internal_semaphore_t *)sem; internal_sem->handle = CreateSemaphore(NULL, value, LONG_MAX, NULL); return internal_sem->handle != 0 ? 0 : -1; } /* * os_semaphore_destroy -- destroys a semaphore instance */ int os_semaphore_destroy(os_semaphore_t *sem) { internal_semaphore_t *internal_sem = (internal_semaphore_t *)sem; BOOL ret = CloseHandle(internal_sem->handle); return ret ? 0 : -1; } /* * os_semaphore_wait -- decreases the value of the semaphore */ int os_semaphore_wait(os_semaphore_t *sem) { internal_semaphore_t *internal_sem = (internal_semaphore_t *)sem; DWORD ret = WaitForSingleObject(internal_sem->handle, INFINITE); return ret == WAIT_OBJECT_0 ? 0 : -1; } /* * os_semaphore_trywait -- tries to decrease the value of the semaphore */ int os_semaphore_trywait(os_semaphore_t *sem) { internal_semaphore_t *internal_sem = (internal_semaphore_t *)sem; DWORD ret = WaitForSingleObject(internal_sem->handle, 0); if (ret == WAIT_TIMEOUT) errno = EAGAIN; return ret == WAIT_OBJECT_0 ? 0 : -1; } /* * os_semaphore_post -- increases the value of the semaphore */ int os_semaphore_post(os_semaphore_t *sem) { internal_semaphore_t *internal_sem = (internal_semaphore_t *)sem; BOOL ret = ReleaseSemaphore(internal_sem->handle, 1, NULL); return ret ? 0 : -1; } pmdk-1.4.1/src/common/os_windows.c000066400000000000000000000325151331545616200171020ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * os_windows.c -- windows abstraction layer */ #include #include #include #include #include "util.h" #include "os.h" #include "out.h" #define UTF8_BOM "\xEF\xBB\xBF" /* * os_open -- open abstraction layer */ int os_open(const char *pathname, int flags, ...) { wchar_t *path = util_toUTF16(pathname); if (path == NULL) return -1; int ret; if (flags & O_CREAT) { va_list arg; va_start(arg, flags); mode_t mode = va_arg(arg, mode_t); va_end(arg); ret = _wopen(path, flags, mode); } else { ret = _wopen(path, flags); } util_free_UTF16(path); /* BOM skipping should not modify errno */ int orig_errno = errno; /* * text files on windows can contain BOM. As we open files * in binary mode we have to detect bom and skip it */ if (ret != -1) { char bom[3]; if (_read(ret, bom, sizeof(bom)) != 3 || memcmp(bom, UTF8_BOM, 3) != 0) { /* UTF-8 bom not found - reset file to the beginning */ _lseek(ret, 0, SEEK_SET); } } errno = orig_errno; return ret; } /* * os_stat -- stat abstraction layer */ int os_stat(const char *pathname, os_stat_t *buf) { wchar_t *path = util_toUTF16(pathname); if (path == NULL) return -1; int ret = _wstat64(path, buf); util_free_UTF16(path); return ret; } /* * os_unlink -- unlink abstraction layer */ int os_unlink(const char *pathname) { wchar_t *path = util_toUTF16(pathname); if (path == NULL) return -1; int ret = _wunlink(path); util_free_UTF16(path); return ret; } /* * os_access -- access abstraction layer */ int os_access(const char *pathname, int mode) { wchar_t *path = util_toUTF16(pathname); if (path == NULL) return -1; int ret = _waccess(path, mode); util_free_UTF16(path); return ret; } /* * os_skipBOM -- (internal) Skip BOM in file stream * * text files on windows can contain BOM. We have to detect bom and skip it. */ static void os_skipBOM(FILE *file) { if (file == NULL) return; /* BOM skipping should not modify errno */ int orig_errno = errno; /* UTF-8 BOM */ uint8_t bom[3]; size_t read_num = fread(bom, sizeof(bom[0]), sizeof(bom), file); if (read_num != ARRAY_SIZE(bom)) goto out; if (memcmp(bom, UTF8_BOM, ARRAY_SIZE(bom)) != 0) { /* UTF-8 bom not found - reset file to the beginning */ fseek(file, 0, SEEK_SET); } out: errno = orig_errno; } /* * os_fopen -- fopen abstraction layer */ FILE * os_fopen(const char *pathname, const char *mode) { wchar_t *path = util_toUTF16(pathname); if (path == NULL) return NULL; wchar_t *wmode = util_toUTF16(mode); if (wmode == NULL) { util_free_UTF16(path); return NULL; } FILE *ret = _wfopen(path, wmode); util_free_UTF16(path); util_free_UTF16(wmode); os_skipBOM(ret); return ret; } /* * os_fdopen -- fdopen abstraction layer */ FILE * os_fdopen(int fd, const char *mode) { FILE *ret = fdopen(fd, mode); os_skipBOM(ret); return ret; } /* * os_chmod -- chmod abstraction layer */ int os_chmod(const char *pathname, mode_t mode) { wchar_t *path = util_toUTF16(pathname); if (path == NULL) return -1; int ret = _wchmod(path, mode); util_free_UTF16(path); return ret; } /* * os_mkstemp -- generate a unique temporary filename from template */ int os_mkstemp(char *temp) { unsigned rnd; wchar_t *utemp = util_toUTF16(temp); if (utemp == NULL) return -1; wchar_t *path = _wmktemp(utemp); if (path == NULL) { util_free_UTF16(utemp); return -1; } wchar_t *npath = Malloc(sizeof(*npath) * wcslen(path) + _MAX_FNAME); if (npath == NULL) { util_free_UTF16(utemp); return -1; } wcscpy(npath, path); util_free_UTF16(utemp); /* * Use rand_s to generate more unique tmp file name than _mktemp do. * In case with multiple threads and multiple files even after close() * file name conflicts occurred. * It resolved issue with synchronous removing * multiples files by system. */ rand_s(&rnd); int ret = _snwprintf(npath + wcslen(npath), _MAX_FNAME, L"%u", rnd); if (ret < 0) goto out; /* * Use O_TEMPORARY flag to make sure the file is deleted when * the last file descriptor is closed. Also, it prevents opening * this file from another process. */ ret = _wopen(npath, O_RDWR | O_CREAT | O_EXCL | O_TEMPORARY, S_IWRITE | S_IREAD); out: Free(npath); return ret; } /* * os_posix_fallocate -- allocate file space */ int os_posix_fallocate(int fd, os_off_t offset, os_off_t len) { /* * From POSIX: * "EINVAL -- The len argument was zero or the offset argument was * less than zero." * * From Linux man-page: * "EINVAL -- offset was less than 0, or len was less than or * equal to 0" */ if (offset < 0 || len <= 0) return EINVAL; /* * From POSIX: * "EFBIG -- The value of offset+len is greater than the maximum * file size." * * Overflow can't be checked for by _chsize_s, since it only gets * the sum. */ if (offset + len < offset) return EFBIG; /* * posix_fallocate should not clobber errno, but * _filelengthi64 might set errno. */ int orig_errno = errno; __int64 current_size = _filelengthi64(fd); int file_length_errno = errno; errno = orig_errno; if (current_size < 0) return file_length_errno; __int64 requested_size = offset + len; if (requested_size <= current_size) return 0; return _chsize_s(fd, requested_size); } /* * os_ftruncate -- truncate a file to a specified length */ int os_ftruncate(int fd, os_off_t length) { return _chsize_s(fd, length); } /* * os_flock -- apply or remove an advisory lock on an open file */ int os_flock(int fd, int operation) { int flags = 0; SYSTEM_INFO systemInfo; GetSystemInfo(&systemInfo); switch (operation & (OS_LOCK_EX | OS_LOCK_SH | OS_LOCK_UN)) { case OS_LOCK_EX: case OS_LOCK_SH: if (operation & OS_LOCK_NB) flags = _LK_NBLCK; else flags = _LK_LOCK; break; case OS_LOCK_UN: flags = _LK_UNLCK; break; default: errno = EINVAL; return -1; } os_off_t filelen = _filelengthi64(fd); if (filelen < 0) return -1; /* for our purpose it's enough to lock the first page of the file */ long len = (filelen > systemInfo.dwPageSize) ? systemInfo.dwPageSize : (long)filelen; int res = _locking(fd, flags, len); if (res != 0 && errno == EACCES) errno = EWOULDBLOCK; /* for consistency with flock() */ return res; } /* * os_writev -- windows version of writev function * * XXX: _write and other similar functions are 32 bit on windows * if size of data is bigger then 2^32, this function * will be not atomic. */ ssize_t os_writev(int fd, const struct iovec *iov, int iovcnt) { size_t size = 0; /* XXX: _write is 32 bit on windows */ for (int i = 0; i < iovcnt; i++) size += iov[i].iov_len; void *buf = malloc(size); if (buf == NULL) return ENOMEM; char *it_buf = buf; for (int i = 0; i < iovcnt; i++) { memcpy(it_buf, iov[i].iov_base, iov[i].iov_len); it_buf += iov[i].iov_len; } ssize_t written = 0; while (size > 0) { int ret = _write(fd, buf, size >= MAXUINT ? MAXUINT : (unsigned)size); if (ret == -1) { written = -1; break; } written += ret; size -= ret; } free(buf); return written; } #define NSEC_IN_SEC 1000000000ull /* number of useconds between 1970-01-01T00:00:00Z and 1601-01-01T00:00:00Z */ #define DELTA_WIN2UNIX (11644473600000000ull) /* * clock_gettime -- returns elapsed time since the system was restarted * or since Epoch, depending on the mode id */ int os_clock_gettime(int id, struct timespec *ts) { switch (id) { case CLOCK_MONOTONIC: { LARGE_INTEGER time; LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&time); ts->tv_sec = time.QuadPart / frequency.QuadPart; ts->tv_nsec = (long)( (time.QuadPart % frequency.QuadPart) * NSEC_IN_SEC / frequency.QuadPart); } break; case CLOCK_REALTIME: { FILETIME ctime_ft; GetSystemTimeAsFileTime(&ctime_ft); ULARGE_INTEGER ctime = { .HighPart = ctime_ft.dwHighDateTime, .LowPart = ctime_ft.dwLowDateTime, }; ts->tv_sec = (ctime.QuadPart - DELTA_WIN2UNIX * 10) / 10000000; ts->tv_nsec = ((ctime.QuadPart - DELTA_WIN2UNIX * 10) % 10000000) * 100; } break; default: SetLastError(EINVAL); return -1; } return 0; } /* * os_setenv -- change or add an environment variable */ int os_setenv(const char *name, const char *value, int overwrite) { errno_t err; /* * If caller doesn't want to overwrite make sure that a environment * variable with the same name doesn't exist. */ if (!overwrite && getenv(name)) return 0; /* * _putenv_s returns a non-zero error code on failure but setenv * needs to return -1 on failure, let's translate the error code. */ if ((err = _putenv_s(name, value)) != 0) { errno = err; return -1; } return 0; } /* * os_unsetenv -- remove an environment variable */ int os_unsetenv(const char *name) { errno_t err; if ((err = _putenv_s(name, "")) != 0) { errno = err; return -1; } return 0; } /* * os_getenv -- getenv abstraction layer */ char * os_getenv(const char *name) { return getenv(name); } /* * rand_r -- rand_r for windows * * XXX: RAND_MAX is equal 0x7fff on Windows, so to get 32 bit random number * we need to merge two numbers returned by rand_s(). * It is not to the best solution as subsequences returned by rand_s are * not guaranteed to be independent. * * XXX: Windows doesn't implement deterministic thread-safe pseudorandom * generator (generator which can be initialized by seed ). * We have to chose between a deterministic nonthread-safe generator * (rand(), srand()) or a non-deterministic thread-safe generator(rand_s()) * as thread-safety is more important, a seed parameter is ignored in this * implementation. */ int os_rand_r(unsigned *seedp) { UNREFERENCED_PARAMETER(seedp); unsigned part1, part2; rand_s(&part1); rand_s(&part2); return part1 << 16 | part2; } /* * sys_siglist -- map of signal to human readable messages like sys_siglist */ const char * const sys_siglist[] = { "Unknown signal 0", /* 0 */ "Hangup", /* 1 */ "Interrupt", /* 2 */ "Quit", /* 3 */ "Illegal instruction", /* 4 */ "Trace/breakpoint trap", /* 5 */ "Aborted", /* 6 */ "Bus error", /* 7 */ "Floating point exception", /* 8 */ "Killed", /* 9 */ "User defined signal 1", /* 10 */ "Segmentation fault", /* 11 */ "User defined signal 2", /* 12 */ "Broken pipe", /* 13 */ "Alarm clock", /* 14 */ "Terminated", /* 15 */ "Stack fault", /* 16 */ "Child exited", /* 17 */ "Continued", /* 18 */ "Stopped (signal)", /* 19 */ "Stopped", /* 20 */ "Stopped (tty input)", /* 21 */ "Stopped (tty output)", /* 22 */ "Urgent I/O condition", /* 23 */ "CPU time limit exceeded", /* 24 */ "File size limit exceeded", /* 25 */ "Virtual timer expired", /* 26 */ "Profiling timer expired", /* 27 */ "Window changed", /* 28 */ "I/O possible", /* 29 */ "Power failure", /* 30 */ "Bad system call", /* 31 */ "Unknown signal 32" /* 32 */ }; int sys_siglist_size = ARRAYSIZE(sys_siglist); /* * string constants for strsignal * XXX: ideally this should have the signal number as the suffix but then we * should use a buffer from thread local storage, so deferring the same till * we need it * NOTE: In Linux strsignal uses TLS for the same reason but if it fails to get * a thread local buffer it falls back to using a static buffer trading the * thread safety. */ #define STR_REALTIME_SIGNAL "Real-time signal" #define STR_UNKNOWN_SIGNAL "Unknown signal" /* * strsignal -- returns a string describing the signal number 'sig' * * XXX: According to POSIX, this one is of type 'char *', but in our * implementation it returns 'const char *'. */ const char * os_strsignal(int sig) { if (sig >= 0 && sig < ARRAYSIZE(sys_siglist)) return sys_siglist[sig]; else if (sig >= 34 && sig <= 64) return STR_REALTIME_SIGNAL; else return STR_UNKNOWN_SIGNAL; } pmdk-1.4.1/src/common/out.c000066400000000000000000000315131331545616200155130ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * out.c -- support for logging, tracing, and assertion output * * Macros like LOG(), OUT, ASSERT(), etc. end up here. */ #include #include #include #include #include #include #include #include "out.h" #include "os.h" #include "os_thread.h" #include "valgrind_internal.h" #include "util.h" /* XXX - modify Linux makefiles to generate srcversion.h and remove #ifdef */ #ifdef _WIN32 #include "srcversion.h" #endif static const char *Log_prefix; static int Log_level; static FILE *Out_fp; static unsigned Log_alignment; #ifndef NO_LIBPTHREAD #define MAXPRINT 8192 /* maximum expected log line */ #else #define MAXPRINT 256 /* maximum expected log line for libpmem */ #endif struct errormsg { char msg[MAXPRINT]; #ifdef _WIN32 wchar_t wmsg[MAXPRINT]; #endif }; #ifndef NO_LIBPTHREAD static os_once_t Last_errormsg_key_once = OS_ONCE_INIT; static os_tls_key_t Last_errormsg_key; static void _Last_errormsg_key_alloc(void) { int pth_ret = os_tls_key_create(&Last_errormsg_key, free); if (pth_ret) FATAL("!os_thread_key_create"); VALGRIND_ANNOTATE_HAPPENS_BEFORE(&Last_errormsg_key_once); } static void Last_errormsg_key_alloc(void) { os_once(&Last_errormsg_key_once, _Last_errormsg_key_alloc); /* * Workaround Helgrind's bug: * https://bugs.kde.org/show_bug.cgi?id=337735 */ VALGRIND_ANNOTATE_HAPPENS_AFTER(&Last_errormsg_key_once); } static inline void Last_errormsg_fini(void) { void *p = os_tls_get(Last_errormsg_key); if (p) { free(p); (void) os_tls_set(Last_errormsg_key, NULL); } (void) os_tls_key_delete(Last_errormsg_key); } static inline struct errormsg * Last_errormsg_get(void) { Last_errormsg_key_alloc(); struct errormsg *errormsg = os_tls_get(Last_errormsg_key); if (errormsg == NULL) { errormsg = malloc(sizeof(struct errormsg)); if (errormsg == NULL) FATAL("!malloc"); /* make sure it contains empty string initially */ errormsg->msg[0] = '\0'; int ret = os_tls_set(Last_errormsg_key, errormsg); if (ret) FATAL("!os_tls_set"); } return errormsg; } #else /* * We don't want libpmem to depend on libpthread. Instead of using pthread * API to dynamically allocate thread-specific error message buffer, we put * it into TLS. However, keeping a pretty large static buffer (8K) in TLS * may lead to some issues, so the maximum message length is reduced. * Fortunately, it looks like the longest error message in libpmem should * not be longer than about 90 chars (in case of pmem_check_version()). */ static __thread struct errormsg Last_errormsg; static inline void Last_errormsg_key_alloc(void) { } static inline void Last_errormsg_fini(void) { } static inline const struct errormsg * Last_errormsg_get(void) { return &Last_errormsg.msg[0]; } #endif /* NO_LIBPTHREAD */ /* * out_init -- initialize the log * * This is called from the library initialization code. */ void out_init(const char *log_prefix, const char *log_level_var, const char *log_file_var, int major_version, int minor_version) { static int once; /* only need to initialize the out module once */ if (once) return; once++; Log_prefix = log_prefix; #ifdef DEBUG char *log_level; char *log_file; if ((log_level = os_getenv(log_level_var)) != NULL) { Log_level = atoi(log_level); if (Log_level < 0) { Log_level = 0; } } if ((log_file = os_getenv(log_file_var)) != NULL && log_file[0] != '\0') { /* reserve more than enough space for a PID + '\0' */ char log_file_pid[PATH_MAX]; size_t len = strlen(log_file); if (len > 0 && log_file[len - 1] == '-') { int ret = snprintf(log_file_pid, PATH_MAX, "%s%d", log_file, getpid()); if (ret < 0 || ret >= PATH_MAX) { ERR("!snprintf"); abort(); } log_file = log_file_pid; } if ((Out_fp = os_fopen(log_file, "w")) == NULL) { char buff[UTIL_MAX_ERR_MSG]; util_strerror(errno, buff, UTIL_MAX_ERR_MSG); fprintf(stderr, "Error (%s): %s=%s: %s\n", log_prefix, log_file_var, log_file, buff); abort(); } } #endif /* DEBUG */ char *log_alignment = os_getenv("PMDK_LOG_ALIGN"); if (log_alignment) { int align = atoi(log_alignment); if (align > 0) Log_alignment = (unsigned)align; } if (Out_fp == NULL) Out_fp = stderr; else setlinebuf(Out_fp); #ifdef DEBUG static char namepath[PATH_MAX]; LOG(1, "pid %d: program: %s", getpid(), util_getexecname(namepath, PATH_MAX)); #endif LOG(1, "%s version %d.%d", log_prefix, major_version, minor_version); static __attribute__((used)) const char *version_msg = "src version: " SRCVERSION; LOG(1, "%s", version_msg); #if VG_PMEMCHECK_ENABLED /* * Attribute "used" to prevent compiler from optimizing out the variable * when LOG expands to no code (!DEBUG) */ static __attribute__((used)) const char *pmemcheck_msg = "compiled with support for Valgrind pmemcheck"; LOG(1, "%s", pmemcheck_msg); #endif /* VG_PMEMCHECK_ENABLED */ #if VG_HELGRIND_ENABLED static __attribute__((used)) const char *helgrind_msg = "compiled with support for Valgrind helgrind"; LOG(1, "%s", helgrind_msg); #endif /* VG_HELGRIND_ENABLED */ #if VG_MEMCHECK_ENABLED static __attribute__((used)) const char *memcheck_msg = "compiled with support for Valgrind memcheck"; LOG(1, "%s", memcheck_msg); #endif /* VG_MEMCHECK_ENABLED */ #if VG_DRD_ENABLED static __attribute__((used)) const char *drd_msg = "compiled with support for Valgrind drd"; LOG(1, "%s", drd_msg); #endif /* VG_DRD_ENABLED */ Last_errormsg_key_alloc(); } /* * out_fini -- close the log file * * This is called to close log file before process stop. */ void out_fini(void) { if (Out_fp != NULL && Out_fp != stderr) { fclose(Out_fp); Out_fp = stderr; } Last_errormsg_fini(); } /* * out_print_func -- default print_func, goes to stderr or Out_fp */ static void out_print_func(const char *s) { /* to suppress drd false-positive */ #ifdef SUPPRESS_FPUTS_DRD_ERROR VALGRIND_ANNOTATE_IGNORE_READS_BEGIN(); VALGRIND_ANNOTATE_IGNORE_WRITES_BEGIN(); #endif fputs(s, Out_fp); #ifdef SUPPRESS_FPUTS_DRD_ERROR VALGRIND_ANNOTATE_IGNORE_READS_END(); VALGRIND_ANNOTATE_IGNORE_WRITES_END(); #endif } /* * calling Print(s) calls the current print_func... */ typedef void (*Print_func)(const char *s); typedef int (*Vsnprintf_func)(char *str, size_t size, const char *format, va_list ap); static Print_func Print = out_print_func; static Vsnprintf_func Vsnprintf = vsnprintf; /* * out_set_print_func -- allow override of print_func used by out module */ void out_set_print_func(void (*print_func)(const char *s)) { LOG(3, "print %p", print_func); Print = (print_func == NULL) ? out_print_func : print_func; } /* * out_set_vsnprintf_func -- allow override of vsnprintf_func used by out module */ void out_set_vsnprintf_func(int (*vsnprintf_func)(char *str, size_t size, const char *format, va_list ap)) { LOG(3, "vsnprintf %p", vsnprintf_func); Vsnprintf = (vsnprintf_func == NULL) ? vsnprintf : vsnprintf_func; } /* * out_snprintf -- (internal) custom snprintf implementation */ FORMAT_PRINTF(3, 4) static int out_snprintf(char *str, size_t size, const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = Vsnprintf(str, size, format, ap); va_end(ap); return (ret); } /* * out_common -- common output code, all output goes through here */ static void out_common(const char *file, int line, const char *func, int level, const char *suffix, const char *fmt, va_list ap) { int oerrno = errno; char buf[MAXPRINT]; unsigned cc = 0; int ret; const char *sep = ""; char errstr[UTIL_MAX_ERR_MSG] = ""; if (file) { char *f = strrchr(file, OS_DIR_SEPARATOR); if (f) file = f + 1; ret = out_snprintf(&buf[cc], MAXPRINT - cc, "<%s>: <%d> [%s:%d %s] ", Log_prefix, level, file, line, func); if (ret < 0) { Print("out_snprintf failed"); goto end; } cc += (unsigned)ret; if (cc < Log_alignment) { memset(buf + cc, ' ', Log_alignment - cc); cc = Log_alignment; } } if (fmt) { if (*fmt == '!') { fmt++; sep = ": "; util_strerror(errno, errstr, UTIL_MAX_ERR_MSG); } ret = Vsnprintf(&buf[cc], MAXPRINT - cc, fmt, ap); if (ret < 0) { Print("Vsnprintf failed"); goto end; } cc += (unsigned)ret; } out_snprintf(&buf[cc], MAXPRINT - cc, "%s%s%s", sep, errstr, suffix); Print(buf); end: errno = oerrno; } /* * out_error -- common error output code, all error messages go through here */ static void out_error(const char *file, int line, const char *func, const char *suffix, const char *fmt, va_list ap) { int oerrno = errno; unsigned cc = 0; int ret; const char *sep = ""; char errstr[UTIL_MAX_ERR_MSG] = ""; char *errormsg = (char *)out_get_errormsg(); if (fmt) { if (*fmt == '!') { fmt++; sep = ": "; util_strerror(errno, errstr, UTIL_MAX_ERR_MSG); } ret = Vsnprintf(&errormsg[cc], MAXPRINT, fmt, ap); if (ret < 0) { strcpy(errormsg, "Vsnprintf failed"); goto end; } cc += (unsigned)ret; out_snprintf(&errormsg[cc], MAXPRINT - cc, "%s%s", sep, errstr); } #ifdef DEBUG if (Log_level >= 1) { char buf[MAXPRINT]; cc = 0; if (file) { char *f = strrchr(file, OS_DIR_SEPARATOR); if (f) file = f + 1; ret = out_snprintf(&buf[cc], MAXPRINT, "<%s>: <1> [%s:%d %s] ", Log_prefix, file, line, func); if (ret < 0) { Print("out_snprintf failed"); goto end; } cc += (unsigned)ret; if (cc < Log_alignment) { memset(buf + cc, ' ', Log_alignment - cc); cc = Log_alignment; } } out_snprintf(&buf[cc], MAXPRINT - cc, "%s%s", errormsg, suffix); Print(buf); } #endif end: errno = oerrno; } /* * out -- output a line, newline added automatically */ void out(const char *fmt, ...) { va_list ap; va_start(ap, fmt); out_common(NULL, 0, NULL, 0, "\n", fmt, ap); va_end(ap); } /* * out_nonl -- output a line, no newline added automatically */ void out_nonl(int level, const char *fmt, ...) { va_list ap; if (Log_level < level) return; va_start(ap, fmt); out_common(NULL, 0, NULL, level, "", fmt, ap); va_end(ap); } /* * out_log -- output a log line if Log_level >= level */ void out_log(const char *file, int line, const char *func, int level, const char *fmt, ...) { va_list ap; if (Log_level < level) return; va_start(ap, fmt); out_common(file, line, func, level, "\n", fmt, ap); va_end(ap); } /* * out_fatal -- output a fatal error & die (i.e. assertion failure) */ void out_fatal(const char *file, int line, const char *func, const char *fmt, ...) { va_list ap; va_start(ap, fmt); out_common(file, line, func, 1, "\n", fmt, ap); va_end(ap); abort(); } /* * out_err -- output an error message */ void out_err(const char *file, int line, const char *func, const char *fmt, ...) { va_list ap; va_start(ap, fmt); out_error(file, line, func, "\n", fmt, ap); va_end(ap); } /* * out_get_errormsg -- get the last error message */ const char * out_get_errormsg(void) { const struct errormsg *errormsg = Last_errormsg_get(); return &errormsg->msg[0]; } #ifdef _WIN32 /* * out_get_errormsgW -- get the last error message in wchar_t */ const wchar_t * out_get_errormsgW(void) { struct errormsg *errormsg = Last_errormsg_get(); const char *utf8 = &errormsg->msg[0]; wchar_t *utf16 = &errormsg->wmsg[0]; if (util_toUTF16_buff(utf8, utf16, sizeof(errormsg->wmsg)) != 0) FATAL("!Failed to convert string"); return (const wchar_t *)utf16; } #endif pmdk-1.4.1/src/common/out.h000066400000000000000000000160201331545616200155140ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * out.h -- definitions for "out" module */ #ifndef PMDK_OUT_H #define PMDK_OUT_H 1 #include #include #include #include "util.h" /* * Suppress errors which are after appropriate ASSERT* macro for nondebug * builds. */ #if !defined(DEBUG) && (defined(__clang_analyzer__) || defined(__COVERITY__)) #define OUT_FATAL_DISCARD_NORETURN __attribute__((noreturn)) #else #define OUT_FATAL_DISCARD_NORETURN #endif #ifndef EVALUATE_DBG_EXPRESSIONS #if defined(DEBUG) || defined(__clang_analyzer__) || defined(__COVERITY__) #define EVALUATE_DBG_EXPRESSIONS 1 #else #define EVALUATE_DBG_EXPRESSIONS 0 #endif #endif #ifdef DEBUG #define OUT_LOG out_log #define OUT_NONL out_nonl #define OUT_FATAL out_fatal #define OUT_FATAL_ABORT out_fatal #else static __attribute__((always_inline)) inline void out_log_discard(const char *file, int line, const char *func, int level, const char *fmt, ...) { (void) file; (void) line; (void) func; (void) level; (void) fmt; } static __attribute__((always_inline)) inline void out_nonl_discard(int level, const char *fmt, ...) { (void) level; (void) fmt; } static __attribute__((always_inline)) OUT_FATAL_DISCARD_NORETURN inline void out_fatal_discard(const char *file, int line, const char *func, const char *fmt, ...) { (void) file; (void) line; (void) func; (void) fmt; } static __attribute__((always_inline)) __attribute__((noreturn)) inline void out_fatal_abort(const char *file, int line, const char *func, const char *fmt, ...) { (void) file; (void) line; (void) func; (void) fmt; abort(); } #define OUT_LOG out_log_discard #define OUT_NONL out_nonl_discard #define OUT_FATAL out_fatal_discard #define OUT_FATAL_ABORT out_fatal_abort #endif /* produce debug/trace output */ #define LOG(level, ...) do { \ if (!EVALUATE_DBG_EXPRESSIONS) break;\ OUT_LOG(__FILE__, __LINE__, __func__, level, __VA_ARGS__);\ } while (0) /* produce debug/trace output without prefix and new line */ #define LOG_NONL(level, ...) do { \ if (!EVALUATE_DBG_EXPRESSIONS) break; \ OUT_NONL(level, __VA_ARGS__); \ } while (0) /* produce output and exit */ #define FATAL(...)\ OUT_FATAL_ABORT(__FILE__, __LINE__, __func__, __VA_ARGS__) /* assert a condition is true at runtime */ #define ASSERT_rt(cnd) do { \ if (!EVALUATE_DBG_EXPRESSIONS || (cnd)) break; \ OUT_FATAL(__FILE__, __LINE__, __func__, "assertion failure: %s", #cnd);\ } while (0) /* assertion with extra info printed if assertion fails at runtime */ #define ASSERTinfo_rt(cnd, info) do { \ if (!EVALUATE_DBG_EXPRESSIONS || (cnd)) break; \ OUT_FATAL(__FILE__, __LINE__, __func__, \ "assertion failure: %s (%s = %s)", #cnd, #info, info);\ } while (0) /* assert two integer values are equal at runtime */ #define ASSERTeq_rt(lhs, rhs) do { \ if (!EVALUATE_DBG_EXPRESSIONS || ((lhs) == (rhs))) break; \ OUT_FATAL(__FILE__, __LINE__, __func__,\ "assertion failure: %s (0x%llx) == %s (0x%llx)", #lhs,\ (unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)); \ } while (0) /* assert two integer values are not equal at runtime */ #define ASSERTne_rt(lhs, rhs) do { \ if (!EVALUATE_DBG_EXPRESSIONS || ((lhs) != (rhs))) break; \ OUT_FATAL(__FILE__, __LINE__, __func__,\ "assertion failure: %s (0x%llx) != %s (0x%llx)", #lhs,\ (unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)); \ } while (0) /* assert a condition is true */ #define ASSERT(cnd)\ do {\ /*\ * Detect useless asserts on always true expression. Please use\ * COMPILE_ERROR_ON(!cnd) or ASSERT_rt(cnd) in such cases.\ */\ if (__builtin_constant_p(cnd))\ ASSERT_COMPILE_ERROR_ON(cnd);\ ASSERT_rt(cnd);\ } while (0) /* assertion with extra info printed if assertion fails */ #define ASSERTinfo(cnd, info)\ do {\ /* See comment in ASSERT. */\ if (__builtin_constant_p(cnd))\ ASSERT_COMPILE_ERROR_ON(cnd);\ ASSERTinfo_rt(cnd, info);\ } while (0) /* assert two integer values are equal */ #define ASSERTeq(lhs, rhs)\ do {\ /* See comment in ASSERT. */\ if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\ ASSERT_COMPILE_ERROR_ON((lhs) == (rhs));\ ASSERTeq_rt(lhs, rhs);\ } while (0) /* assert two integer values are not equal */ #define ASSERTne(lhs, rhs)\ do {\ /* See comment in ASSERT. */\ if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\ ASSERT_COMPILE_ERROR_ON((lhs) != (rhs));\ ASSERTne_rt(lhs, rhs);\ } while (0) #define ERR(...)\ out_err(__FILE__, __LINE__, __func__, __VA_ARGS__) void out_init(const char *log_prefix, const char *log_level_var, const char *log_file_var, int major_version, int minor_version); void out_fini(void); void out(const char *fmt, ...) FORMAT_PRINTF(1, 2); void out_nonl(int level, const char *fmt, ...) FORMAT_PRINTF(2, 3); void out_log(const char *file, int line, const char *func, int level, const char *fmt, ...) FORMAT_PRINTF(5, 6); void out_err(const char *file, int line, const char *func, const char *fmt, ...) FORMAT_PRINTF(4, 5); void out_fatal(const char *file, int line, const char *func, const char *fmt, ...) FORMAT_PRINTF(4, 5) __attribute__((noreturn)); void out_set_print_func(void (*print_func)(const char *s)); void out_set_vsnprintf_func(int (*vsnprintf_func)(char *str, size_t size, const char *format, va_list ap)); #ifdef _WIN32 #ifndef PMDK_UTF8_API #define out_get_errormsg out_get_errormsgW #else #define out_get_errormsg out_get_errormsgU #endif #endif #ifndef _WIN32 const char *out_get_errormsg(void); #else const char *out_get_errormsgU(void); const wchar_t *out_get_errormsgW(void); #endif #endif pmdk-1.4.1/src/common/plugin.c000066400000000000000000000127401331545616200162030ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * plugin.c -- infrastructure for plugins */ #include #include #include #include "util.h" #include "out.h" #include "plugin.h" #include "dlsym.h" struct plugin { const char *module_name; /* identifier of the upper layer module */ const char *name; /* unique identifier */ unsigned version; /* struct version, bump on incompatibilities */ void *funcs; /* the plugin itself */ void *handle; /* shared library handle */ int loaded; /* has the pmem_plugin_load function been called? */ struct plugin_ops p_ops; SLIST_ENTRY(plugin) e; }; static SLIST_HEAD(, plugin) plugins; #define PMEM_PLUGIN_LOAD_SYMBOL(plugin, symbol, path, error)\ if (((plugin)->p_ops.symbol = util_dlsym((plugin)->handle, #symbol)) == NULL) {\ LOG(3, "%s: unable to load %s symbol", (path), #symbol);\ goto error; } /* * plugin_new_entry -- creates new plugin entry in the plugins list */ static int plugin_new_entry(const char *plugin_path) { LOG(3, "%s", plugin_path); struct plugin *p = Malloc(sizeof(*p)); if (p == NULL) { LOG(3, "%s: unable to allocate plugin", plugin_path); goto error_plugin_alloc; } p->loaded = 0; p->handle = util_dlopen(plugin_path); if (p->handle == NULL) { LOG(3, "%s: unable to dlopen plugin (%s)", plugin_path, util_dlerror()); goto error_plugin_open; } PMEM_PLUGIN_LOAD_SYMBOL(p, pmem_plugin_desc, plugin_path, error_symbol); PMEM_PLUGIN_LOAD_SYMBOL(p, pmem_plugin_load, plugin_path, error_symbol); PMEM_PLUGIN_LOAD_SYMBOL(p, pmem_plugin_unload, plugin_path, error_symbol); p->p_ops.pmem_plugin_desc(&p->module_name, &p->name, &p->version, &p->funcs); SLIST_INSERT_HEAD(&plugins, p, e); return 0; error_symbol: util_dlclose(p->handle); error_plugin_open: Free(p); error_plugin_alloc: return -1; } /* * plugin_init -- initializes plugin module */ int plugin_init(const char *plugin_dir) { LOG(3, "%s", plugin_dir); struct dirent *entry; DIR *pdir = opendir(plugin_dir); if (pdir == NULL) return -1; size_t dirlen = strlen(plugin_dir); char *plugin_path = Malloc(dirlen + PATH_MAX + 1); if (plugin_path == NULL) { closedir(pdir); return -1; } strcpy(plugin_path, plugin_dir); plugin_path[dirlen] = '/'; while ((entry = readdir(pdir)) != NULL) { const char *extension = strrchr(entry->d_name, '.'); if (extension == NULL || strcmp(extension, ".so") != 0) continue; strcpy(plugin_path + dirlen + 1, entry->d_name); plugin_new_entry(plugin_path); } closedir(pdir); Free(plugin_path); return 0; } /* * plugin_fini -- unloads all plugins and the module */ void plugin_fini(void) { LOG(3, NULL); struct plugin *p; while (!SLIST_EMPTY(&plugins)) { p = SLIST_FIRST(&plugins); SLIST_REMOVE_HEAD(&plugins, e); if (p->loaded) p->p_ops.pmem_plugin_unload(); if (p->handle != NULL) util_dlclose(p->handle); Free(p); } } /* * plugin_add -- add a static plugin */ int plugin_add(const struct plugin_ops *p_ops) { LOG(3, NULL); struct plugin *p = Malloc(sizeof(*p)); if (p == NULL) { LOG(3, "unable to allocate static plugin"); return -1; } p->loaded = 0; p->handle = NULL; p->p_ops = *p_ops; p->p_ops.pmem_plugin_desc(&p->module_name, &p->name, &p->version, &p->funcs); SLIST_INSERT_HEAD(&plugins, p, e); return 0; } /* * plugin_load -- traverses the plugins list, searching for compatible ones */ void plugin_load(const char *module_name, unsigned version, void (*plugin_cb)(const char *name, void *funcs, void *arg), void *arg) { LOG(3, "module_name %s version %u", module_name, version); struct plugin *p; SLIST_FOREACH(p, &plugins, e) { if (strcmp(module_name, p->module_name) != 0) continue; if (version != p->version) continue; if (!p->loaded) { if (p->p_ops.pmem_plugin_load() != 0) { ERR("unable to load %s plugin", p->name); continue; } p->loaded = 1; LOG(3, "loaded %s plugin from module %s", p->name, p->module_name); } plugin_cb(p->name, p->funcs, arg); } } pmdk-1.4.1/src/common/plugin.h000066400000000000000000000040551331545616200162100ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * plugin.h -- infrastructure for plugins */ struct plugin_ops { void (*pmem_plugin_desc)(const char **module_name, const char **name, unsigned *version, void **funcs); int (*pmem_plugin_load)(void); void (*pmem_plugin_unload)(void); }; int plugin_init(const char *plugin_dir); void plugin_fini(void); int plugin_add(const struct plugin_ops *p_ops); void plugin_load(const char *module_name, unsigned version, void (*plugin_cb)(const char *name, void *funcs, void *arg), void *arg); pmdk-1.4.1/src/common/pmemcommon.h000066400000000000000000000041001331545616200170500ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pmemcommon.h -- definitions for "common" module */ #ifndef PMEMCOMMON_H #define PMEMCOMMON_H 1 #include "util.h" #include "out.h" #include "mmap.h" static inline void common_init(const char *log_prefix, const char *log_level_var, const char *log_file_var, int major_version, int minor_version) { util_init(); out_init(log_prefix, log_level_var, log_file_var, major_version, minor_version); util_mmap_init(); } static inline void common_fini(void) { util_mmap_fini(); out_fini(); } #endif pmdk-1.4.1/src/common/pmemcommon.inc000066400000000000000000000040551331545616200174030ustar00rootroot00000000000000# Copyright 2017-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # src/pmemcommon.inc -- common SOURCE definitions for PMDK libraries # SOURCE =\ $(COMMON)/file.c\ $(COMMON)/file_posix.c\ $(COMMON)/fs_posix.c\ $(COMMON)/mmap.c\ $(COMMON)/mmap_posix.c\ $(COMMON)/os_posix.c\ $(COMMON)/os_thread_posix.c\ $(COMMON)/os_dimm_$(OS_DIMM).c\ $(COMMON)/os_deep_linux.c\ $(COMMON)/os_auto_flush_linux.c\ $(COMMON)/out.c\ $(COMMON)/pool_hdr.c\ $(COMMON)/set.c\ $(COMMON)/shutdown_state.c\ $(COMMON)/util.c\ $(COMMON)/util_posix.c\ $(COMMON)/uuid.c\ $(call osdep, $(COMMON)/uuid,.c) pmdk-1.4.1/src/common/pool_hdr.c000066400000000000000000000132061331545616200165110ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pool_hdr.c -- pool header utilities */ #include #include #include #include #include "out.h" #include "pool_hdr.h" /* Determine ISA for which PMDK is currently compiled */ #if defined(__x86_64) || defined(_M_X64) /* x86 -- 64 bit */ #define PMDK_MACHINE PMDK_MACHINE_X86_64 #define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64 #elif defined(__aarch64__) /* 64 bit ARM not supported yet */ #define PMDK_MACHINE PMDK_MACHINE_AARCH64 #define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64 #else /* add appropriate definitions here when porting PMDK to another ISA */ #error unable to recognize ISA at compile time #endif /* * arch_machine -- (internal) determine endianness */ static uint8_t arch_data(void) { uint16_t word = (PMDK_DATA_BE << 8) + PMDK_DATA_LE; return ((uint8_t *)&word)[0]; } /* * util_get_arch_flags -- get architecture identification flags */ void util_get_arch_flags(struct arch_flags *arch_flags) { memset(arch_flags, 0, sizeof(*arch_flags)); arch_flags->machine = PMDK_MACHINE; arch_flags->machine_class = PMDK_MACHINE_CLASS; arch_flags->data = arch_data(); arch_flags->alignment_desc = alignment_desc(); } /* * util_convert2le_hdr -- convert pool_hdr into little-endian byte order */ void util_convert2le_hdr(struct pool_hdr *hdrp) { hdrp->major = htole32(hdrp->major); hdrp->compat_features = htole32(hdrp->compat_features); hdrp->incompat_features = htole32(hdrp->incompat_features); hdrp->ro_compat_features = htole32(hdrp->ro_compat_features); hdrp->arch_flags.alignment_desc = htole64(hdrp->arch_flags.alignment_desc); hdrp->arch_flags.machine = htole16(hdrp->arch_flags.machine); hdrp->crtime = htole64(hdrp->crtime); hdrp->checksum = htole64(hdrp->checksum); } /* * util_convert2h_hdr_nocheck -- convert pool_hdr into host byte order */ void util_convert2h_hdr_nocheck(struct pool_hdr *hdrp) { hdrp->major = le32toh(hdrp->major); hdrp->compat_features = le32toh(hdrp->compat_features); hdrp->incompat_features = le32toh(hdrp->incompat_features); hdrp->ro_compat_features = le32toh(hdrp->ro_compat_features); hdrp->crtime = le64toh(hdrp->crtime); hdrp->arch_flags.machine = le16toh(hdrp->arch_flags.machine); hdrp->arch_flags.alignment_desc = le64toh(hdrp->arch_flags.alignment_desc); hdrp->checksum = le64toh(hdrp->checksum); } /* * util_arch_flags_check -- validates arch_flags */ int util_check_arch_flags(const struct arch_flags *arch_flags) { struct arch_flags cur_af; int ret = 0; util_get_arch_flags(&cur_af); if (!util_is_zeroed(&arch_flags->reserved, sizeof(arch_flags->reserved))) { ERR("invalid reserved values"); ret = -1; } if (arch_flags->machine != cur_af.machine) { ERR("invalid machine value"); ret = -1; } if (arch_flags->data != cur_af.data) { ERR("invalid data value"); ret = -1; } if (arch_flags->machine_class != cur_af.machine_class) { ERR("invalid machine_class value"); ret = -1; } if (arch_flags->alignment_desc != cur_af.alignment_desc) { ERR("invalid alignment_desc value"); ret = -1; } return ret; } /* * util_feature_check -- check features masks */ int util_feature_check(struct pool_hdr *hdrp, uint32_t incompat, uint32_t ro_compat, uint32_t compat) { LOG(3, "hdrp %p incompat %#x ro_compat %#x compat %#x", hdrp, incompat, ro_compat, compat); #define GET_NOT_MASKED_BITS(x, mask) ((x) & ~(mask)) uint32_t ubits; /* unsupported bits */ /* check incompatible ("must support") features */ ubits = GET_NOT_MASKED_BITS(hdrp->incompat_features, incompat); if (ubits) { ERR("unsafe to continue due to unknown incompat "\ "features: %#x", ubits); errno = EINVAL; return -1; } /* check RO-compatible features (force RO if unsupported) */ ubits = GET_NOT_MASKED_BITS(hdrp->ro_compat_features, ro_compat); if (ubits) { ERR("switching to read-only mode due to unknown ro_compat "\ "features: %#x", ubits); return 0; } /* check compatible ("may") features */ ubits = GET_NOT_MASKED_BITS(hdrp->compat_features, compat); if (ubits) { LOG(3, "ignoring unknown compat features: %#x", ubits); } #undef GET_NOT_MASKED_BITS return 1; } pmdk-1.4.1/src/common/pool_hdr.h000066400000000000000000000145151331545616200165220ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pool_hdr.h -- internal definitions for pool header module */ #ifndef PMDK_POOL_HDR_H #define PMDK_POOL_HDR_H 1 #include #include #include #include "uuid.h" #include "shutdown_state.h" /* * Number of bits per type in alignment descriptor */ #define ALIGNMENT_DESC_BITS 4 /* * architecture identification flags * * These flags allow to unambiguously determine the architecture * on which the pool was created. * * The alignment_desc field contains information about alignment * of the following basic types: * - char * - short * - int * - long * - long long * - size_t * - os_off_t * - float * - double * - long double * - void * * * The alignment of each type is computed as an offset of field * of specific type in the following structure: * struct { * char byte; * type field; * }; * * The value is decremented by 1 and masked by 4 bits. * Multiple alignments are stored on consecutive 4 bits of each * type in the order specified above. * * The values used in the machine, and machine_class fields are in * principle independent of operating systems, and object formats. * In practice they happen to match constants used in ELF object headers. */ struct arch_flags { uint64_t alignment_desc; /* alignment descriptor */ uint8_t machine_class; /* address size -- 64 bit or 32 bit */ uint8_t data; /* data encoding -- LE or BE */ uint8_t reserved[4]; uint16_t machine; /* required architecture */ }; #define POOL_HDR_ARCH_LEN sizeof(struct arch_flags) /* possible values of the machine class field in the above struct */ #define PMDK_MACHINE_CLASS_64 2 /* 64 bit pointers, 64 bit size_t */ /* possible values of the machine field in the above struct */ #define PMDK_MACHINE_X86_64 62 #define PMDK_MACHINE_AARCH64 183 /* possible values of the data field in the above struct */ #define PMDK_DATA_LE 1 /* 2's complement, little endian */ #define PMDK_DATA_BE 2 /* 2's complement, big endian */ /* * header used at the beginning of all types of memory pools * * for pools build on persistent memory, the integer types * below are stored in little-endian byte order. */ #define POOL_HDR_SIG_LEN 8 /* * defines the first not checksumed field - all fields after this will be * ignored during checksum calculations */ #define POOL_HDR_CSUM_END_OFF offsetof(struct pool_hdr, unused2) struct pool_hdr { char signature[POOL_HDR_SIG_LEN]; uint32_t major; /* format major version number */ uint32_t compat_features; /* mask: compatible "may" features */ uint32_t incompat_features; /* mask: "must support" features */ uint32_t ro_compat_features; /* mask: force RO if unsupported */ uuid_t poolset_uuid; /* pool set UUID */ uuid_t uuid; /* UUID of this file */ uuid_t prev_part_uuid; /* prev part */ uuid_t next_part_uuid; /* next part */ uuid_t prev_repl_uuid; /* prev replica */ uuid_t next_repl_uuid; /* next replica */ uint64_t crtime; /* when created (seconds since epoch) */ struct arch_flags arch_flags; /* architecture identification flags */ unsigned char unused[1888]; /* must be zero */ /* not checksumed */ unsigned char unused2[1992]; /* must be zero */ struct shutdown_state sds; /* shutdown status */ uint64_t checksum; /* checksum of above fields */ }; #define POOL_HDR_SIZE (sizeof(struct pool_hdr)) #define POOL_DESC_SIZE 4096 void util_convert2le_hdr(struct pool_hdr *hdrp); void util_convert2h_hdr_nocheck(struct pool_hdr *hdrp); void util_get_arch_flags(struct arch_flags *arch_flags); int util_check_arch_flags(const struct arch_flags *arch_flags); int util_feature_check(struct pool_hdr *hdrp, uint32_t incompat, uint32_t ro_compat, uint32_t compat); /* * set of macros for determining the alignment descriptor */ #define DESC_MASK ((1 << ALIGNMENT_DESC_BITS) - 1) #define alignment_of(t) offsetof(struct { char c; t x; }, x) #define alignment_desc_of(t) (((uint64_t)alignment_of(t) - 1) & DESC_MASK) #define alignment_desc()\ (alignment_desc_of(char) << 0 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(short) << 1 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(int) << 2 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(long) << 3 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(long long) << 4 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(size_t) << 5 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(off_t) << 6 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(float) << 7 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(double) << 8 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(long double) << 9 * ALIGNMENT_DESC_BITS) |\ (alignment_desc_of(void *) << 10 * ALIGNMENT_DESC_BITS) /* * incompat features */ #define POOL_FEAT_SINGLEHDR 0x0001 /* pool header only in the first part */ #define POOL_FEAT_CKSUM_2K 0x0002 /* only first 2K of hdr checksummed */ #define POOL_FEAT_ALL (POOL_FEAT_SINGLEHDR | POOL_FEAT_CKSUM_2K) #endif pmdk-1.4.1/src/common/queue.h000066400000000000000000000520021331545616200160310ustar00rootroot00000000000000/* * Source: glibc 2.24 (git://sourceware.org/glibc.git /misc/sys/queue.h) * * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * A singly-linked list is headed by a single forward pointer. The * elements are singly linked for minimum space and pointer manipulation * overhead at the expense of O(n) removal for arbitrary elements. New * elements can be added to the list after an existing element or at the * head of the list. Elements being removed from the head of the list * should use the explicit macro for this purpose for optimum * efficiency. A singly-linked list may only be traversed in the forward * direction. Singly-linked lists are ideal for applications with large * datasets and few or no removals or for implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ /* * XXX This is a workaround for a bug in the llvm's static analyzer. For more * info see https://github.com/pmem/issues/issues/309. */ #ifdef __clang_analyzer__ static void custom_assert(void) { abort(); } #define ANALYZER_ASSERT(x) (__builtin_expect(!(x), 0) ? (void)0 : custom_assert()) #else #define ANALYZER_ASSERT(x) do {} while (0) #endif /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #ifdef __cplusplus #define _CAST_AND_ASSIGN(x, y) x = (__typeof__(x))y; #else #define _CAST_AND_ASSIGN(x, y) x = (void *)(y); #endif #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List functions. */ #define LIST_INIT(head) do { \ (head)->lh_first = NULL; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (/*CONSTCOND*/0) #define LIST_REMOVE(elm, field) do { \ ANALYZER_ASSERT(elm != NULL); \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_FOREACH(var, head, field) \ for ((var) = ((head)->lh_first); \ (var); \ (var) = ((var)->field.le_next)) /* * List access methods. */ #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) #define LIST_NEXT(elm, field) ((elm)->field.le_next) /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List functions. */ #define SLIST_INIT(head) do { \ (head)->slh_first = NULL; \ } while (/*CONSTCOND*/0) #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (/*CONSTCOND*/0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (/*CONSTCOND*/0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (/*CONSTCOND*/0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = (head)->slh_first; \ while(curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ } \ } while (/*CONSTCOND*/0) #define SLIST_FOREACH(var, head, field) \ for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) /* * Singly-linked List access methods. */ #define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) /* * Singly-linked Tail queue declarations. */ #define STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first; /* first element */ \ struct type **stqh_last; /* addr of last next element */ \ } #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } #define STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } /* * Singly-linked Tail queue functions. */ #define STAILQ_INIT(head) do { \ (head)->stqh_first = NULL; \ (head)->stqh_last = &(head)->stqh_first; \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ (head)->stqh_first = (elm); \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.stqe_next = NULL; \ *(head)->stqh_last = (elm); \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ (head)->stqh_last = &(elm)->field.stqe_next; \ (listelm)->field.stqe_next = (elm); \ } while (/*CONSTCOND*/0) #define STAILQ_REMOVE_HEAD(head, field) do { \ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ (head)->stqh_last = &(head)->stqh_first; \ } while (/*CONSTCOND*/0) #define STAILQ_REMOVE(head, elm, type, field) do { \ if ((head)->stqh_first == (elm)) { \ STAILQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->stqh_first; \ while (curelm->field.stqe_next != (elm)) \ curelm = curelm->field.stqe_next; \ if ((curelm->field.stqe_next = \ curelm->field.stqe_next->field.stqe_next) == NULL) \ (head)->stqh_last = &(curelm)->field.stqe_next; \ } \ } while (/*CONSTCOND*/0) #define STAILQ_FOREACH(var, head, field) \ for ((var) = ((head)->stqh_first); \ (var); \ (var) = ((var)->field.stqe_next)) #define STAILQ_CONCAT(head1, head2) do { \ if (!STAILQ_EMPTY((head2))) { \ *(head1)->stqh_last = (head2)->stqh_first; \ (head1)->stqh_last = (head2)->stqh_last; \ STAILQ_INIT((head2)); \ } \ } while (/*CONSTCOND*/0) /* * Singly-linked Tail queue access methods. */ #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) #define STAILQ_FIRST(head) ((head)->stqh_first) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE(head, elm, type, field) do { \ if ((head)->sqh_first == (elm)) { \ SIMPLEQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->sqh_first; \ while (curelm->field.sqe_next != (elm)) \ curelm = curelm->field.sqe_next; \ if ((curelm->field.sqe_next = \ curelm->field.sqe_next->field.sqe_next) == NULL) \ (head)->sqh_last = &(curelm)->field.sqe_next; \ } \ } while (/*CONSTCOND*/0) #define SIMPLEQ_FOREACH(var, head, field) \ for ((var) = ((head)->sqh_first); \ (var); \ (var) = ((var)->field.sqe_next)) /* * Simple queue access methods. */ #define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) /* * Tail queue definitions. */ #define _TAILQ_HEAD(name, type, qual) \ struct name { \ qual type *tqh_first; /* first element */ \ qual type *qual *tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define _TAILQ_ENTRY(type, qual) \ struct { \ qual type *tqe_next; /* next element */ \ qual type *qual *tqe_prev; /* address of previous next element */\ } #define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_REMOVE(head, elm, field) do { \ ANALYZER_ASSERT(elm != NULL); \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_FOREACH(var, head, field) \ for ((var) = ((head)->tqh_first); \ (var); \ (var) = ((var)->field.tqe_next)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ (var); \ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) #define TAILQ_CONCAT(head1, head2, field) do { \ if (!TAILQ_EMPTY(head2)) { \ *(head1)->tqh_last = (head2)->tqh_first; \ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ (head1)->tqh_last = (head2)->tqh_last; \ TAILQ_INIT((head2)); \ } \ } while (/*CONSTCOND*/0) /* * Tail queue access methods. */ #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { (void *)&head, (void *)&head } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ _CAST_AND_ASSIGN((head)->cqh_first, (head)); \ _CAST_AND_ASSIGN((head)->cqh_last, (head)); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = (void *)(head); \ if ((head)->cqh_last == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ _CAST_AND_ASSIGN((elm)->field.cqe_next, (head)); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ } while (/*CONSTCOND*/0) #define CIRCLEQ_FOREACH(var, head, field) \ for ((var) = ((head)->cqh_first); \ (var) != (const void *)(head); \ (var) = ((var)->field.cqe_next)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for ((var) = ((head)->cqh_last); \ (var) != (const void *)(head); \ (var) = ((var)->field.cqe_prev)) /* * Circular queue access methods. */ #define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_LOOP_NEXT(head, elm, field) \ (((elm)->field.cqe_next == (void *)(head)) \ ? ((head)->cqh_first) \ : (elm->field.cqe_next)) #define CIRCLEQ_LOOP_PREV(head, elm, field) \ (((elm)->field.cqe_prev == (void *)(head)) \ ? ((head)->cqh_last) \ : (elm->field.cqe_prev)) /* * Sorted queue functions. */ #define SORTEDQ_HEAD(name, type) CIRCLEQ_HEAD(name, type) #define SORTEDQ_HEAD_INITIALIZER(head) CIRCLEQ_HEAD_INITIALIZER(head) #define SORTEDQ_ENTRY(type) CIRCLEQ_ENTRY(type) #define SORTEDQ_INIT(head) CIRCLEQ_INIT(head) #define SORTEDQ_INSERT(head, elm, field, type, comparer) { \ type *_elm_it; \ for (_elm_it = (head)->cqh_first; \ ((_elm_it != (void *)(head)) && \ (comparer(_elm_it, (elm)) < 0)); \ _elm_it = _elm_it->field.cqe_next) \ /*NOTHING*/; \ if (_elm_it == (void *)(head)) \ CIRCLEQ_INSERT_TAIL(head, elm, field); \ else \ CIRCLEQ_INSERT_BEFORE(head, _elm_it, elm, field); \ } #define SORTEDQ_REMOVE(head, elm, field) CIRCLEQ_REMOVE(head, elm, field) #define SORTEDQ_FOREACH(var, head, field) CIRCLEQ_FOREACH(var, head, field) #define SORTEDQ_FOREACH_REVERSE(var, head, field) \ CIRCLEQ_FOREACH_REVERSE(var, head, field) /* * Sorted queue access methods. */ #define SORTEDQ_EMPTY(head) CIRCLEQ_EMPTY(head) #define SORTEDQ_FIRST(head) CIRCLEQ_FIRST(head) #define SORTEDQ_LAST(head) CIRCLEQ_LAST(head) #define SORTEDQ_NEXT(elm, field) CIRCLEQ_NEXT(elm, field) #define SORTEDQ_PREV(elm, field) CIRCLEQ_PREV(elm, field) #endif /* sys/queue.h */ pmdk-1.4.1/src/common/set.c000066400000000000000000003057331331545616200155070ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * set.c -- pool set utilities */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libpmem.h" #include "librpmem.h" #include "set.h" #include "file.h" #include "os.h" #include "mmap.h" #include "util.h" #include "out.h" #include "dlsym.h" #include "valgrind_internal.h" #include "sys_util.h" #include "util_pmem.h" #include "fs.h" #include "os_deep.h" #define LIBRARY_REMOTE "librpmem.so.1" #define SIZE_AUTODETECT_STR "AUTO" #define PMEM_EXT ".pmem" #define PMEM_EXT_LEN sizeof(PMEM_EXT) #define PMEM_FILE_PADDING 6 #define PMEM_FILE_NAME_MAX_LEN 20 #define PMEM_FILE_MAX_LEN (PMEM_FILE_NAME_MAX_LEN + PMEM_FILE_PADDING) static RPMEMpool *(*Rpmem_create)(const char *target, const char *pool_set_name, void *pool_addr, size_t pool_size, unsigned *nlanes, const struct rpmem_pool_attr *rpmem_attr); static RPMEMpool *(*Rpmem_open)(const char *target, const char *pool_set_name, void *pool_addr, size_t pool_size, unsigned *nlanes, struct rpmem_pool_attr *rpmem_attr); int (*Rpmem_close)(RPMEMpool *rpp); int (*Rpmem_persist)(RPMEMpool *rpp, size_t offset, size_t length, unsigned lane); int (*Rpmem_deep_persist)(RPMEMpool *rpp, size_t offset, size_t length, unsigned lane); int (*Rpmem_read)(RPMEMpool *rpp, void *buff, size_t offset, size_t length, unsigned lane); int (*Rpmem_remove)(const char *target, const char *pool_set_name, int flags); int (*Rpmem_set_attr)(RPMEMpool *rpp, const struct rpmem_pool_attr *rattr); static int Remote_replication_available; static os_mutex_t Remote_lock; static void *Rpmem_handle_remote; int Prefault_at_open = 0; int Prefault_at_create = 0; /* list of pool set option names and flags */ static struct pool_set_option Options[] = { { "SINGLEHDR", OPTION_SINGLEHDR }, #ifndef _WIN32 { "NOHDRS", OPTION_NOHDRS }, #endif { NULL, OPTION_UNKNOWN } }; /* * util_remote_init -- initialize remote replication */ void util_remote_init(void) { LOG(3, NULL); /* XXX Is duplicate initialization really okay? */ if (!Remote_replication_available) { util_mutex_init(&Remote_lock); Remote_replication_available = 1; } } /* * util_remote_fini -- finalize remote replication */ void util_remote_fini(void) { LOG(3, NULL); util_remote_unload(); /* XXX Okay to be here if not initialized? */ if (Remote_replication_available) { Remote_replication_available = 0; util_mutex_destroy(&Remote_lock); } } /* * util_dl_check_error -- check libdl error */ static int util_dl_check_error(void *handle, const char *func) { LOG(15, "handle %p func %s", handle, func); if (handle == NULL) { char *errstr = util_dlerror(); if (errstr) ERR("%s(): %s", func, errstr); errno = ELIBACC; return -1; } return 0; } /* * util_remote_unload_core -- (internal) unload remote library (core function) */ static void util_remote_unload_core(void) { if (Rpmem_handle_remote != NULL) { util_dlclose(Rpmem_handle_remote); Rpmem_handle_remote = NULL; } Rpmem_create = NULL; Rpmem_open = NULL; Rpmem_close = NULL; Rpmem_persist = NULL; Rpmem_deep_persist = NULL; Rpmem_read = NULL; Rpmem_remove = NULL; Rpmem_set_attr = NULL; } /* * util_remote_unload -- unload remote library */ void util_remote_unload(void) { LOG(3, NULL); if (!Remote_replication_available) return; util_mutex_lock(&Remote_lock); util_remote_unload_core(); util_mutex_unlock(&Remote_lock); } /* * util_remote_load -- load remote library */ int util_remote_load(void) { LOG(3, NULL); if (!Remote_replication_available) { ERR("remote replication is not available"); return -1; } CHECK_FUNC_COMPATIBLE(rpmem_create, *Rpmem_create); CHECK_FUNC_COMPATIBLE(rpmem_open, *Rpmem_open); CHECK_FUNC_COMPATIBLE(rpmem_close, *Rpmem_close); CHECK_FUNC_COMPATIBLE(rpmem_persist, *Rpmem_persist); CHECK_FUNC_COMPATIBLE(rpmem_deep_persist, *Rpmem_deep_persist); CHECK_FUNC_COMPATIBLE(rpmem_read, *Rpmem_read); CHECK_FUNC_COMPATIBLE(rpmem_remove, *Rpmem_remove); util_mutex_lock(&Remote_lock); if (Rpmem_handle_remote) goto end; Rpmem_handle_remote = util_dlopen(LIBRARY_REMOTE); if (util_dl_check_error(Rpmem_handle_remote, "dlopen")) { ERR("the pool set requires a remote replica, " "but the '%s' library cannot be loaded", LIBRARY_REMOTE); goto err; } Rpmem_create = util_dlsym(Rpmem_handle_remote, "rpmem_create"); if (util_dl_check_error(Rpmem_create, "dlsym")) { ERR("symbol 'rpmem_create' not found"); goto err; } Rpmem_open = util_dlsym(Rpmem_handle_remote, "rpmem_open"); if (util_dl_check_error(Rpmem_open, "dlsym")) { ERR("symbol 'rpmem_open' not found"); goto err; } Rpmem_close = util_dlsym(Rpmem_handle_remote, "rpmem_close"); if (util_dl_check_error(Rpmem_close, "dlsym")) { ERR("symbol 'rpmem_close' not found"); goto err; } Rpmem_persist = util_dlsym(Rpmem_handle_remote, "rpmem_persist"); if (util_dl_check_error(Rpmem_persist, "dlsym")) { ERR("symbol 'rpmem_persist' not found"); goto err; } Rpmem_deep_persist = util_dlsym(Rpmem_handle_remote, "rpmem_deep_persist"); if (util_dl_check_error(Rpmem_deep_persist, "dlsym")) { ERR("symbol 'rpmem_deep_persist' not found"); goto err; } Rpmem_read = util_dlsym(Rpmem_handle_remote, "rpmem_read"); if (util_dl_check_error(Rpmem_read, "dlsym")) { ERR("symbol 'rpmem_read' not found"); goto err; } Rpmem_remove = util_dlsym(Rpmem_handle_remote, "rpmem_remove"); if (util_dl_check_error(Rpmem_remove, "dlsym")) { ERR("symbol 'rpmem_remove' not found"); goto err; } Rpmem_set_attr = util_dlsym(Rpmem_handle_remote, "rpmem_set_attr"); if (util_dl_check_error(Rpmem_set_attr, "dlsym")) { ERR("symbol 'rpmem_set_attr' not found"); goto err; } end: util_mutex_unlock(&Remote_lock); return 0; err: LOG(4, "error clean up"); util_remote_unload_core(); util_mutex_unlock(&Remote_lock); return -1; } /* reserve space for size, path and some whitespace and/or comment */ #define PARSER_MAX_LINE (PATH_MAX + 1024) enum parser_codes { PARSER_CONTINUE = 0, PARSER_PMEMPOOLSET, PARSER_REPLICA, PARSER_INVALID_TOKEN, PARSER_REMOTE_REPLICA_EXPECTED, PARSER_WRONG_SIZE, PARSER_CANNOT_READ_SIZE, PARSER_ABSOLUTE_PATH_EXPECTED, PARSER_RELATIVE_PATH_EXPECTED, PARSER_SET_NO_PARTS, PARSER_REP_NO_PARTS, PARSER_REMOTE_REP_UNEXPECTED_PARTS, PARSER_SIZE_MISMATCH, PARSER_OUT_OF_MEMORY, PARSER_OPTION_UNKNOWN, PARSER_OPTION_EXPECTED, PARSER_FORMAT_OK, PARSER_MAX_CODE }; static const char *parser_errstr[PARSER_MAX_CODE] = { "", /* parsing */ "the first line must be exactly 'PMEMPOOLSET'", "exactly 'REPLICA' expected", "invalid token found in the current line", "address of remote node and descriptor of remote pool set expected", "incorrect format of size", "cannot determine size of a part", "incorrect path (must be an absolute one)", "incorrect descriptor (must be a relative path)", "no pool set parts", "no replica parts", "unexpected parts for remote replica", "sizes of pool set and replica mismatch", "allocating memory failed", "unknown option", "missing option name", "" /* format correct */ }; /* * util_replica_force_page_allocation - (internal) forces page allocation for * replica */ static void util_replica_force_page_allocation(struct pool_replica *rep) { volatile char *cur_addr = rep->part[0].addr; char *addr_end = (char *)cur_addr + rep->resvsize; for (; cur_addr < addr_end; cur_addr += Pagesize) { *cur_addr = *cur_addr; VALGRIND_SET_CLEAN(cur_addr, 1); } } /* * util_map_hdr -- map a header of a pool set */ int util_map_hdr(struct pool_set_part *part, int flags, int rdonly) { LOG(3, "part %p flags %d", part, flags); COMPILE_ERROR_ON(POOL_HDR_SIZE == 0); ASSERTeq(POOL_HDR_SIZE % Pagesize, 0); /* * Workaround for Device DAX not allowing to map a portion * of the device if offset/length are not aligned to the internal * device alignment (page size). I.e. if the device alignment * is 2M, we cannot map the 4K header, but need to align the mapping * length to 2M. * * According to mmap(2), system should automatically align mapping * length to be a multiple of the underlying page size, but it's * not true for Device DAX. */ size_t hdrsize = part->alignment > POOL_HDR_SIZE ? part->alignment : POOL_HDR_SIZE; void *addr = NULL; #if VG_MEMCHECK_ENABLED if (On_valgrind) { /* this is required only for Device DAX & memcheck */ addr = util_map_hint(hdrsize, hdrsize); if (addr == MAP_FAILED) { ERR("cannot find a contiguous region of given size"); /* there's nothing we can do */ return -1; } } #endif int prot = rdonly ? PROT_READ : PROT_READ|PROT_WRITE; void *hdrp = util_map_sync(addr, hdrsize, prot, flags, part->fd, 0, &part->hdr_map_sync); if (hdrp == MAP_FAILED) { ERR("!mmap: %s", part->path); return -1; } part->hdrsize = hdrsize; part->hdr = hdrp; VALGRIND_REGISTER_PMEM_MAPPING(part->hdr, part->hdrsize); VALGRIND_REGISTER_PMEM_FILE(part->fd, part->hdr, part->hdrsize, 0); return 0; } /* * util_unmap_hdr -- unmap pool set part header */ int util_unmap_hdr(struct pool_set_part *part) { if (part->hdr != NULL && part->hdrsize != 0) { LOG(4, "munmap: addr %p size %zu", part->hdr, part->hdrsize); VALGRIND_REMOVE_PMEM_MAPPING(part->hdr, part->hdrsize); if (munmap(part->hdr, part->hdrsize) != 0) { ERR("!munmap: %s", part->path); } part->hdr = NULL; part->hdrsize = 0; } return 0; } /* * util_map_part -- map a part of a pool set */ int util_map_part(struct pool_set_part *part, void *addr, size_t size, size_t offset, int flags, int rdonly) { LOG(3, "part %p addr %p size %zu offset %zu flags %d", part, addr, size, offset, flags); ASSERTeq((uintptr_t)addr % Mmap_align, 0); ASSERTeq(offset % Mmap_align, 0); ASSERTeq(size % Mmap_align, 0); ASSERT(((os_off_t)offset) >= 0); ASSERTeq(offset % part->alignment, 0); ASSERT(offset < part->filesize); if (!size) size = (part->filesize - offset) & ~(part->alignment - 1); else size = roundup(size, part->alignment); int prot = rdonly ? PROT_READ : PROT_READ | PROT_WRITE; void *addrp = util_map_sync(addr, size, prot, flags, part->fd, (os_off_t)offset, &part->map_sync); if (addrp == MAP_FAILED) { ERR("!mmap: %s", part->path); return -1; } if (addr != NULL && (flags & MAP_FIXED) && addrp != addr) { ERR("unable to map at requested address %p", addr); munmap(addrp, size); return -1; } part->addr = addrp; part->size = size; VALGRIND_REGISTER_PMEM_MAPPING(part->addr, part->size); VALGRIND_REGISTER_PMEM_FILE(part->fd, part->addr, part->size, offset); return 0; } /* * util_unmap_part -- unmap a part of a pool set */ int util_unmap_part(struct pool_set_part *part) { LOG(3, "part %p", part); if (part->addr != NULL && part->size != 0) { LOG(4, "munmap: addr %p size %zu", part->addr, part->size); VALGRIND_REMOVE_PMEM_MAPPING(part->addr, part->size); if (munmap(part->addr, part->size) != 0) { ERR("!munmap: %s", part->path); } part->addr = NULL; part->size = 0; } return 0; } /* * util_unmap_parts -- unmap parts from start_index to the end_index */ int util_unmap_parts(struct pool_replica *rep, unsigned start_index, unsigned end_index) { LOG(3, "rep: %p, start_index: %u, end_index: %u", rep, start_index, end_index); for (unsigned p = start_index; p <= end_index; p++) util_unmap_part(&rep->part[p]); return 0; } /* * util_poolset_free -- free pool set info */ void util_poolset_free(struct pool_set *set) { LOG(3, "set %p", set); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; if (rep->remote == NULL) { /* only local replicas have paths */ for (unsigned p = 0; p < rep->nallocated; p++) { Free((void *)(rep->part[p].path)); } } else { /* remote replica */ ASSERTeq(rep->nparts, 1); Free(rep->remote->node_addr); Free(rep->remote->pool_desc); Free(rep->remote); } struct pool_set_directory *d; VEC_FOREACH_BY_PTR(d, &rep->directory) { Free((void *)d->path); } VEC_DELETE(&rep->directory); Free(set->replica[r]); } Free(set); } /* * util_poolset_open -- open all replicas from a poolset */ int util_poolset_open(struct pool_set *set) { for (unsigned r = 0; r < set->nreplicas; ++r) { if (util_replica_open(set, r, MAP_SHARED)) { LOG(2, "replica open failed: replica %u", r); errno = EINVAL; return -1; } } return 0; } /* * util_replica_close_local -- close local replica, optionally delete the * replica's parts */ int util_replica_close_local(struct pool_replica *rep, unsigned repn, enum del_parts_mode del) { for (unsigned p = 0; p < rep->nparts; p++) { if (rep->part[p].fd != -1) (void) os_close(rep->part[p].fd); if ((del == DELETE_CREATED_PARTS && rep->part[p].created) || del == DELETE_ALL_PARTS) { LOG(4, "unlink %s", rep->part[p].path); int olderrno = errno; if (util_unlink(rep->part[p].path) && errno != ENOENT) { ERR("!unlink %s failed (part %u, replica %u)", rep->part[p].path, p, repn); return -1; } errno = olderrno; } } return 0; } /* * util_replica_close_remote -- close remote replica, optionally delete the * replica */ int util_replica_close_remote(struct pool_replica *rep, unsigned repn, enum del_parts_mode del) { if (!rep->remote) return 0; if (rep->remote->rpp) { LOG(4, "closing remote replica #%u", repn); Rpmem_close(rep->remote->rpp); rep->remote->rpp = NULL; } if ((del == DELETE_CREATED_PARTS && rep->part[0].created) || del == DELETE_ALL_PARTS) { LOG(4, "removing remote replica #%u", repn); int ret = Rpmem_remove(rep->remote->node_addr, rep->remote->pool_desc, 0); if (ret) { LOG(1, "!removing remote replica #%u failed", repn); return -1; } } return 0; } /* * util_poolset_close -- unmap and close all the parts of the pool set, * optionally delete parts */ void util_poolset_close(struct pool_set *set, enum del_parts_mode del) { LOG(3, "set %p del %d", set, del); int oerrno = errno; for (unsigned r = 0; r < set->nreplicas; r++) { util_replica_close(set, r); struct pool_replica *rep = set->replica[r]; if (!rep->remote) (void) util_replica_close_local(rep, r, del); else (void) util_replica_close_remote(rep, r, del); } /* * XXX On FreeBSD, mmap()ing a file does not increment the flock() * reference count, so we had to keep the files open until now. */ #ifdef __FreeBSD__ util_poolset_fdclose_always(set); #endif util_poolset_free(set); errno = oerrno; } /* * util_poolset_chmod -- change mode for all created files related to pool set */ int util_poolset_chmod(struct pool_set *set, mode_t mode) { LOG(3, "set %p mode %o", set, mode); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; /* skip remote replicas */ if (rep->remote != NULL) continue; for (unsigned p = 0; p < rep->nparts; p++) { struct pool_set_part *part = &rep->part[p]; /* skip not created or closed parts */ if (!part->created || part->fd == -1) continue; os_stat_t stbuf; if (os_fstat(part->fd, &stbuf) != 0) { ERR("!fstat %d %s", part->fd, part->path); return -1; } if (stbuf.st_mode & ~(unsigned)S_IFMT) { LOG(1, "file permissions changed during pool " "initialization, file: %s (%o)", part->path, stbuf.st_mode & ~(unsigned)S_IFMT); } if (os_chmod(part->path, mode)) { ERR("!chmod %u/%u/%s", r, p, part->path); return -1; } } } return 0; } /* * util_poolset_fdclose_always -- close file descriptors related to pool set */ void util_poolset_fdclose_always(struct pool_set *set) { LOG(3, "set %p", set); for (unsigned r = 0; r < set->nreplicas; r++) util_replica_fdclose(set->replica[r]); } /* * util_poolset_fdclose -- close pool set file descriptors if not FreeBSD * * XXX On FreeBSD, mmap()ing a file does not increment the flock() * reference count, so we need to keep the files open. */ void util_poolset_fdclose(struct pool_set *set) { #ifdef __FreeBSD__ LOG(3, "set %p: holding open", set); #else util_poolset_fdclose_always(set); #endif } /* * util_autodetect_size -- (internal) retrieves size of an existing file */ static ssize_t util_autodetect_size(const char *path) { if (!util_file_is_device_dax(path)) { ERR("size autodetection is supported only for device dax"); return -1; } return util_file_get_size(path); } /* * parser_read_line -- (internal) read line and validate size and path * from a pool set file */ static enum parser_codes parser_read_line(char *line, size_t *size, char **path) { int ret; char *size_str; char *path_str; char *rest_str; char *saveptr = NULL; /* must be NULL initialized on Windows */ size_str = strtok_r(line, " \t", &saveptr); path_str = strtok_r(NULL, " \t", &saveptr); rest_str = strtok_r(NULL, " \t", &saveptr); if (!size_str || !path_str || rest_str) return PARSER_INVALID_TOKEN; LOG(10, "size '%s' path '%s'", size_str, path_str); /* * A format of the size is checked in detail. As regards the path, * it is checked only if the read path is an absolute path. * The rest should be checked during creating/opening the file. */ /* check if the read path is an absolute path */ if (!util_is_absolute_path(path_str)) return PARSER_ABSOLUTE_PATH_EXPECTED; *path = Strdup(path_str); if (!(*path)) { ERR("!Strdup"); return PARSER_OUT_OF_MEMORY; } if (strcmp(SIZE_AUTODETECT_STR, size_str) == 0) { /* * XXX: this should be done after the parsing completes, but * currently this operation is performed in simply too many * places in the code to move this someplace else. */ ssize_t s = util_autodetect_size(path_str); if (s < 0) { Free(*path); *path = NULL; return PARSER_CANNOT_READ_SIZE; } *size = (size_t)s; return PARSER_CONTINUE; } ret = util_parse_size(size_str, size); if (ret != 0 || *size == 0) { Free(*path); *path = NULL; return PARSER_WRONG_SIZE; } return PARSER_CONTINUE; } /* * parser_read_replica -- (internal) read line and validate remote replica * from a pool set file */ static enum parser_codes parser_read_replica(char *line, char **node_addr, char **pool_desc) { char *addr_str; char *desc_str; char *rest_str; char *saveptr = NULL; /* must be NULL initialized on Windows */ addr_str = strtok_r(line, " \t", &saveptr); desc_str = strtok_r(NULL, " \t", &saveptr); rest_str = strtok_r(NULL, " \t", &saveptr); if (!addr_str || !desc_str) return PARSER_REMOTE_REPLICA_EXPECTED; if (rest_str) return PARSER_INVALID_TOKEN; LOG(10, "node address '%s' pool set descriptor '%s'", addr_str, desc_str); /* check if the descriptor is a relative path */ if (util_is_absolute_path(desc_str)) return PARSER_RELATIVE_PATH_EXPECTED; *node_addr = Strdup(addr_str); *pool_desc = Strdup(desc_str); if (!(*node_addr) || !(*pool_desc)) { ERR("!Strdup"); if (*node_addr) Free(*node_addr); if (*pool_desc) Free(*pool_desc); return PARSER_OUT_OF_MEMORY; } return PARSER_CONTINUE; } /* * parser_read_options -- (internal) read line and validate options */ static enum parser_codes parser_read_options(char *line, unsigned *options) { LOG(3, "line '%s'", line); int opt_cnt = 0; char *saveptr = NULL; /* must be NULL initialized on Windows */ char *opt_str = strtok_r(line, " \t", &saveptr); while (opt_str != NULL) { LOG(4, "option '%s'", opt_str); int i = 0; while (Options[i].name && strcmp(opt_str, Options[i].name) != 0) i++; if (Options[i].name == NULL) { LOG(4, "unknown option '%s'", opt_str); return PARSER_OPTION_UNKNOWN; } if (*options & Options[i].flag) LOG(4, "duplicated option '%s'", opt_str); *options |= Options[i].flag; opt_cnt++; opt_str = strtok_r(NULL, " \t", &saveptr); } if (opt_cnt == 0) return PARSER_OPTION_EXPECTED; return PARSER_CONTINUE; } /* * util_replica_reserve -- reserves part slots capacity in a replica */ static int util_replica_reserve(struct pool_replica **repp, unsigned n) { LOG(3, "replica %p n %u", *repp, n); struct pool_replica *rep = *repp; if (rep->nallocated >= n) return 0; rep = Realloc(rep, sizeof(struct pool_replica) + (n) * sizeof(struct pool_set_part)); if (rep == NULL) { ERR("!Realloc"); return -1; } size_t nsize = sizeof(struct pool_set_part) * (n - rep->nallocated); memset(rep->part + rep->nallocated, 0, nsize); rep->nallocated = n; *repp = rep; return 0; } /* * util_replica_add_part_by_idx -- (internal) allocates, initializes and adds a * part structure at the provided location in the replica info */ static int util_replica_add_part_by_idx(struct pool_replica **repp, const char *path, size_t filesize, unsigned p) { LOG(3, "replica %p path %s filesize %zu", *repp, path, filesize); if (util_replica_reserve(repp, p + 1) != 0) return -1; struct pool_replica *rep = *repp; ASSERTne(rep, NULL); int is_dev_dax = util_file_is_device_dax(path); rep->part[p].path = path; rep->part[p].filesize = filesize; rep->part[p].fd = -1; rep->part[p].is_dev_dax = is_dev_dax; rep->part[p].created = 0; rep->part[p].hdr = NULL; rep->part[p].addr = NULL; rep->part[p].remote_hdr = NULL; if (is_dev_dax) rep->part[p].alignment = util_file_device_dax_alignment(path); else rep->part[p].alignment = Mmap_align; ASSERTne(rep->part[p].alignment, 0); rep->nparts += 1; return 0; } /* * util_replica_add_part -- adds a next part in replica info */ static int util_replica_add_part(struct pool_replica **repp, const char *path, size_t filesize) { LOG(3, "replica %p path \"%s\" filesize %zu", *repp, path, filesize); return util_replica_add_part_by_idx(repp, path, filesize, (*repp)->nparts); } /* * util_parse_add_part -- (internal) add a new part file to the replica info */ static int util_parse_add_part(struct pool_set *set, const char *path, size_t filesize) { LOG(3, "set %p path %s filesize %zu", set, path, filesize); ASSERTne(set, NULL); if (set->directory_based) { ERR("cannot mix directories and files in a set"); errno = EINVAL; return -1; } return util_replica_add_part(&set->replica[set->nreplicas - 1], path, filesize); } /* * util_parse_add_directory -- * (internal) add a new directory to the replica info */ static int util_parse_add_directory(struct pool_set *set, const char *path, size_t filesize) { LOG(3, "set %p path %s filesize %zu", set, path, filesize); ASSERTne(set, NULL); struct pool_replica *rep = set->replica[set->nreplicas - 1]; ASSERTne(rep, NULL); if (set->directory_based == 0) { if (rep->nparts > 0 || set->nreplicas > 1) { ERR("cannot mix directories and files in a set"); errno = EINVAL; return -1; } set->directory_based = 1; } char *rpath = util_part_realpath(path); if (rpath == NULL) { ERR("cannot resolve realpath of new directory"); return -1; } for (unsigned i = 0; i < set->nreplicas; ++i) { struct pool_replica *r = set->replica[i]; struct pool_set_directory *dir; char *dpath = NULL; VEC_FOREACH_BY_PTR(dir, &r->directory) { dpath = util_part_realpath(dir->path); ASSERTne(dpath, NULL); /* must have been resolved */ if (strcmp(rpath, dpath) == 0) { ERR("cannot use the same directory twice"); errno = EEXIST; free(dpath); free(rpath); return -1; } free(dpath); } } free(rpath); struct pool_set_directory d; d.path = path; d.resvsize = filesize; VEC_PUSH_BACK(&rep->directory, d); rep->resvsize += filesize; return 0; } /* * util_parse_add_element -- * (internal) add a new element to the replica info */ static int util_parse_add_element(struct pool_set *set, const char *path, size_t filesize) { LOG(3, "set %p path %s filesize %zu", set, path, filesize); os_stat_t stat; int olderrno = errno; if (os_stat(path, &stat) == 0 && S_ISDIR(stat.st_mode)) return util_parse_add_directory(set, path, filesize); errno = olderrno; return util_parse_add_part(set, path, filesize); } /* * util_parse_add_replica -- (internal) add a new replica to the pool set info */ static int util_parse_add_replica(struct pool_set **setp) { LOG(3, "setp %p", setp); ASSERTne(setp, NULL); struct pool_set *set = *setp; ASSERTne(set, NULL); set = Realloc(set, sizeof(struct pool_set) + (set->nreplicas + 1) * sizeof(struct pool_replica *)); if (set == NULL) { ERR("!Realloc"); return -1; } *setp = set; struct pool_replica *rep; rep = Zalloc(sizeof(struct pool_replica)); if (rep == NULL) { ERR("!Malloc"); return -1; } VEC_INIT(&rep->directory); unsigned r = set->nreplicas++; set->replica[r] = rep; return 0; } /* * util_replica_check_map_sync -- (internal) check MAP_SYNC restrictions */ static int util_replica_check_map_sync(struct pool_set *set, unsigned repidx, int check_hdr) { LOG(3, "set %p repidx %u", set, repidx); struct pool_replica *rep = set->replica[repidx]; int map_sync = rep->part[0].map_sync; for (unsigned p = 1; p < rep->nparts; p++) { if (map_sync != rep->part[p].map_sync) { ERR("replica #%u part %u %smapped with MAP_SYNC", repidx, p, rep->part[p].map_sync ? "" : "not"); return -1; } } if (check_hdr) { for (unsigned p = 0; p < rep->nhdrs; p++) { if (map_sync != rep->part[p].hdr_map_sync) { ERR("replica #%u part %u header %smapped " "with MAP_SYNC", repidx, p, rep->part[p].hdr_map_sync ? "" : "not"); return -1; } } } return 0; } /* * util_poolset_check_devdax -- (internal) check Device DAX restrictions */ static int util_poolset_check_devdax(struct pool_set *set) { LOG(3, "set %p", set); if (set->directory_based) return 0; for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; int is_dev_dax = rep->part[0].is_dev_dax; for (unsigned p = 0; p < rep->nparts; p++) { if (rep->part[p].is_dev_dax != is_dev_dax) { ERR( "either all the parts must be Device DAX or none"); return -1; } if (is_dev_dax && rep->nparts > 1 && (set->options & (OPTION_SINGLEHDR | OPTION_NOHDRS)) == 0 && util_file_device_dax_alignment(rep->part[p].path) != Pagesize) { ERR( "Multiple DAX devices with alignment other than 4KB. Use the SINGLEHDR poolset option."); return -1; } } } return 0; } /* * util_poolset_check_options -- (internal) check if poolset options are * admissible */ static int util_poolset_check_options(struct pool_set *set) { LOG(3, "set %p", set); if ((set->options & OPTION_SINGLEHDR) && (set->options & OPTION_NOHDRS)) { ERR( "both SINGLEHDR and NOHDR poolset options used at the same time"); return -1; } return 0; } /* * util_poolset_set_size -- (internal) calculate pool size */ static void util_poolset_set_size(struct pool_set *set) { LOG(3, "set %p", set); set->poolsize = SIZE_MAX; set->resvsize = SIZE_MAX; for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; if (set->options & OPTION_SINGLEHDR) rep->nhdrs = 1; else if (set->options & OPTION_NOHDRS) rep->nhdrs = 0; else rep->nhdrs = rep->nparts; rep->repsize = 0; for (unsigned p = 0; p < rep->nparts; p++) { rep->repsize += (rep->part[p].filesize & ~(Mmap_align - 1)); } if (rep->nhdrs > 0) rep->repsize -= (rep->nhdrs - 1) * Mmap_align; if (rep->resvsize == 0) rep->resvsize = rep->repsize; /* * Calculate pool size - choose the smallest replica size. * Ignore remote replicas. */ if (rep->remote == NULL && rep->repsize < set->poolsize) set->poolsize = rep->repsize; if (rep->remote == NULL && rep->resvsize < set->resvsize) set->resvsize = rep->resvsize; } LOG(3, "pool size set to %zu", set->poolsize); } /* * util_parse_add_remote_replica -- (internal) add a new remote replica * to the pool set info */ static int util_parse_add_remote_replica(struct pool_set **setp, char *node_addr, char *pool_desc) { LOG(3, "setp %p node_addr %s pool_desc %s", setp, node_addr, pool_desc); ASSERTne(setp, NULL); ASSERTne(node_addr, NULL); ASSERTne(pool_desc, NULL); int ret = util_parse_add_replica(setp); if (ret != 0) return ret; /* * A remote replica has one fake part of size equal twice pool header * size for storing pool header and pool descriptor. */ ret = util_parse_add_part(*setp, NULL, 2 * POOL_HDR_SIZE); if (ret != 0) return ret; struct pool_set *set = *setp; struct pool_replica *rep = set->replica[set->nreplicas - 1]; ASSERTne(rep, NULL); rep->remote = Zalloc(sizeof(struct remote_replica)); if (rep->remote == NULL) { ERR("!Malloc"); return -1; } rep->remote->node_addr = node_addr; rep->remote->pool_desc = pool_desc; set->remote = 1; return 0; } /* * util_readline -- read line from stream */ static char * util_readline(FILE *fh) { LOG(10, "fh %p", fh); size_t bufsize = PARSER_MAX_LINE; size_t position = 0; char *buffer = NULL; do { char *tmp = buffer; buffer = Realloc(buffer, bufsize); if (buffer == NULL) { Free(tmp); return NULL; } /* ensure if we can cast bufsize to int */ ASSERT(bufsize / 2 <= INT_MAX); ASSERT((bufsize - position) >= (bufsize / 2)); char *s = util_fgets(buffer + position, (int)bufsize / 2, fh); if (s == NULL) { Free(buffer); return NULL; } position = strlen(buffer); bufsize *= 2; } while (!feof(fh) && buffer[position - 1] != '\n'); return buffer; } /* * util_part_idx_by_file_name -- (internal) retrieves the part index from a * name of the file that is an element of a directory poolset */ static long util_part_idx_by_file_name(const char *filename) { LOG(3, "filename \"%s\"", filename); int olderrno = errno; errno = 0; long part_idx = strtol(filename, NULL, 10); if (errno != 0) return -1; errno = olderrno; return part_idx; } /* * util_poolset_directory_load -- (internal) loads and initializes all * existing parts in a single directory */ static int util_poolset_directory_load(struct pool_replica **repp, const char *directory) { LOG(3, "rep %p dir \"%s\"", *repp, directory); struct fs *f = fs_new(directory); if (f == NULL) { ERR("!fs_new: \"%s\"", directory); return -1; } int nparts = 0; char *path = NULL; struct fs_entry *entry; while ((entry = fs_read(f)) != NULL) { if (entry->level != 1) continue; if (entry->type != FS_ENTRY_FILE) continue; if (entry->namelen < PMEM_EXT_LEN) continue; const char *ext = entry->path + entry->pathlen - PMEM_EXT_LEN + 1; if (strcmp(PMEM_EXT, ext) != 0) continue; long part_idx = util_part_idx_by_file_name(entry->name); if (part_idx < 0) continue; ssize_t size = util_file_get_size(entry->path); if (size < 0) { LOG(2, "cannot read size of file (%s) in a poolset directory", entry->path); goto err; } if ((path = Strdup(entry->path)) == NULL) { ERR("!Strdup"); goto err; } if (util_replica_add_part_by_idx(repp, path, (size_t)size, (unsigned)part_idx) != 0) { ERR("unable to load part %s", entry->path); goto err; } nparts++; } fs_delete(f); return nparts; err: fs_delete(f); return -1; } /* * util_poolset_directories_load -- (internal) loads and initializes all * existing parts in the poolset directories */ static int util_poolset_directories_load(struct pool_set *set) { LOG(3, "set %p", set); if (!set->directory_based) return 0; unsigned next_part_id = 0; unsigned max_parts_rep = 0; for (unsigned r = 0; r < set->nreplicas; r++) { next_part_id = 0; struct pool_set_directory *d; int nparts = 0; int prev_nparts = 0; VEC_FOREACH_BY_PTR(d, &set->replica[r]->directory) { prev_nparts = nparts; nparts = util_poolset_directory_load(&set->replica[r], d->path); if (nparts < 0) { ERR("failed to load parts from directory %s", d->path); return -1; } next_part_id += (unsigned)nparts; /* always try to evenly spread files across dirs */ if (r == 0 && prev_nparts > nparts) set->next_directory_id++; } if (next_part_id > set->replica[max_parts_rep]->nparts) max_parts_rep = r; if (r == 0) set->next_id = next_part_id; } /* * In order to maintain the same semantics of poolset parsing for * regular poolsets and directory poolsets, we need to speculatively * recreate the information regarding any missing parts in replicas. */ struct pool_replica *rep; struct pool_replica *mrep = set->replica[max_parts_rep]; for (unsigned r = 0; r < set->nreplicas; r++) { if (set->replica[r]->nparts == mrep->nparts) continue; if (VEC_SIZE(&set->replica[r]->directory) == 0) { ERR("no directories in replica"); return -1; } if (util_replica_reserve(&set->replica[r], mrep->nparts) != 0) return -1; rep = set->replica[r]; struct pool_set_directory *d = VEC_GET(&rep->directory, 0); for (unsigned pidx = 0; pidx < rep->nallocated; ++pidx) { struct pool_set_part *p = &rep->part[pidx]; *p = mrep->part[pidx]; size_t path_len = strlen(d->path) + PMEM_FILE_MAX_LEN; if ((p->path = Malloc(path_len)) == NULL) { ERR("!Malloc"); return -1; } snprintf((char *)p->path, path_len, "%s" OS_DIR_SEP_STR "%0*u%s", d->path, PMEM_FILE_PADDING, pidx, PMEM_EXT); } rep->nparts = mrep->nparts; } return 0; } /* * util_poolset_parse -- parse pool set config file * * Returns 0 if the file is a valid poolset config file, * and -1 in case of any error. * * XXX: use memory mapped file */ int util_poolset_parse(struct pool_set **setp, const char *path, int fd) { LOG(3, "setp %p path %s fd %d", setp, path, fd); struct pool_set *set = NULL; enum parser_codes result; char *line; char *ppath; char *pool_desc; char *node_addr; char *cp; size_t psize; FILE *fs; int oerrno; if (os_lseek(fd, 0, SEEK_SET) != 0) { ERR("!lseek %d", fd); return -1; } fd = dup(fd); if (fd < 0) { ERR("!dup"); return -1; } /* associate a stream with the file descriptor */ if ((fs = os_fdopen(fd, "r")) == NULL) { ERR("!fdopen %d", fd); os_close(fd); return -1; } unsigned nlines = 0; unsigned nparts = 0; /* number of parts in current replica */ /* read the first line */ line = util_readline(fs); if (line == NULL) { ERR("!Reading poolset file"); goto err; } nlines++; set = Zalloc(sizeof(struct pool_set)); if (set == NULL) { ERR("!Malloc for pool set"); goto err; } /* check also if the last character is '\n' */ if (strncmp(line, POOLSET_HDR_SIG, POOLSET_HDR_SIG_LEN) == 0 && line[POOLSET_HDR_SIG_LEN] == '\n') { /* 'PMEMPOOLSET' signature detected */ LOG(10, "PMEMPOOLSET"); int ret = util_parse_add_replica(&set); if (ret != 0) goto err; nparts = 0; result = PARSER_CONTINUE; } else { result = PARSER_PMEMPOOLSET; } while (result == PARSER_CONTINUE) { Free(line); /* read next line */ line = util_readline(fs); nlines++; if (line) { /* chop off newline and comments */ if ((cp = strchr(line, '\n')) != NULL) *cp = '\0'; if (cp != line && (cp = strchr(line, '#')) != NULL) *cp = '\0'; /* skip comments and blank lines */ if (cp == line) continue; } if (!line) { if (nparts >= 1) { result = PARSER_FORMAT_OK; } else { if (set->nreplicas == 1) result = PARSER_SET_NO_PARTS; else result = PARSER_REP_NO_PARTS; } } else if (strncmp(line, POOLSET_OPTION_SIG, POOLSET_OPTION_SIG_LEN) == 0) { result = parser_read_options( line + POOLSET_OPTION_SIG_LEN, &set->options); if (result == PARSER_CONTINUE) { LOG(10, "OPTIONS: %x", set->options); } } else if (strncmp(line, POOLSET_REPLICA_SIG, POOLSET_REPLICA_SIG_LEN) == 0) { if (line[POOLSET_REPLICA_SIG_LEN] != '\0') { /* something more than 'REPLICA' */ char c = line[POOLSET_REPLICA_SIG_LEN]; if (!isblank((unsigned char)c)) { result = PARSER_REPLICA; continue; } /* check if it is a remote replica */ result = parser_read_replica( line + POOLSET_REPLICA_SIG_LEN, &node_addr, &pool_desc); if (result == PARSER_CONTINUE) { /* remote REPLICA */ LOG(10, "REMOTE REPLICA " "node address '%s' " "pool set descriptor '%s'", node_addr, pool_desc); if (util_parse_add_remote_replica(&set, node_addr, pool_desc)) goto err; } } else if (nparts >= 1) { /* 'REPLICA' signature detected */ LOG(10, "REPLICA"); int ret = util_parse_add_replica(&set); if (ret != 0) goto err; nparts = 0; result = PARSER_CONTINUE; } else { if (set->nreplicas == 1) result = PARSER_SET_NO_PARTS; else result = PARSER_REP_NO_PARTS; } } else { /* there could be no parts for remote replicas */ if (set->replica[set->nreplicas - 1]->remote) { result = PARSER_REMOTE_REP_UNEXPECTED_PARTS; continue; } /* read size and path */ result = parser_read_line(line, &psize, &ppath); if (result == PARSER_CONTINUE) { /* add a new pool's part to the list */ int ret = util_parse_add_element(set, ppath, psize); if (ret != 0) { Free(ppath); goto err; } nparts++; } } } if (result != PARSER_FORMAT_OK) { ERR("%s [%s:%d]", path, parser_errstr[result], nlines); switch (result) { case PARSER_CANNOT_READ_SIZE: case PARSER_OUT_OF_MEMORY: /* do not overwrite errno */ break; default: errno = EINVAL; } goto err; } if (util_poolset_check_devdax(set) != 0) { errno = EINVAL; goto err; } if (util_poolset_directories_load(set) != 0) { ERR("cannot load part files from directories"); goto err; } LOG(4, "set file format correct (%s)", path); (void) os_fclose(fs); Free(line); util_poolset_check_options(set); util_poolset_set_size(set); *setp = set; return 0; err: oerrno = errno; Free(line); (void) os_fclose(fs); if (set) util_poolset_free(set); errno = oerrno; return -1; } /* * util_poolset_single -- (internal) create a one-part pool set * * On success returns a pointer to a newly allocated and initialized * pool set structure. Otherwise, NULL is returned. */ static struct pool_set * util_poolset_single(const char *path, size_t filesize, int create, int ignore_sds) { LOG(3, "path %s filesize %zu create %d", path, filesize, create); struct pool_set *set; set = Zalloc(sizeof(struct pool_set) + sizeof(struct pool_replica *)); if (set == NULL) { ERR("!Malloc for pool set"); return NULL; } struct pool_replica *rep; rep = Zalloc(sizeof(struct pool_replica) + sizeof(struct pool_set_part)); if (rep == NULL) { ERR("!Malloc for pool set replica"); Free(set); return NULL; } VEC_INIT(&rep->directory); set->replica[0] = rep; rep->part[0].filesize = filesize; rep->part[0].path = Strdup(path); rep->part[0].fd = -1; /* will be filled out by util_poolset_file() */ rep->part[0].is_dev_dax = util_file_is_device_dax(path); rep->part[0].created = create; rep->part[0].hdr = NULL; rep->part[0].addr = NULL; if (rep->part[0].is_dev_dax) rep->part[0].alignment = util_file_device_dax_alignment(path); else rep->part[0].alignment = Mmap_align; ASSERTne(rep->part[0].alignment, 0); rep->nallocated = 1; rep->nparts = 1; rep->nhdrs = 1; /* it does not have a remote replica */ rep->remote = NULL; set->remote = 0; /* round down to the nearest mapping alignment boundary */ rep->repsize = rep->part[0].filesize & ~(rep->part[0].alignment - 1); rep->resvsize = rep->repsize; set->poolsize = rep->repsize; set->resvsize = rep->resvsize; set->nreplicas = 1; set->ignore_sds = ignore_sds; return set; } /* * util_part_open -- open or create a single part file */ int util_part_open(struct pool_set_part *part, size_t minsize, int create) { LOG(3, "part %p minsize %zu create %d", part, minsize, create); /* check if file exists */ if (os_access(part->path, F_OK) == 0) create = 0; part->created = 0; if (create) { part->fd = util_file_create(part->path, part->filesize, minsize); if (part->fd == -1) { LOG(2, "failed to create file: %s", part->path); return -1; } part->created = 1; } else { size_t size = 0; int flags = O_RDWR; part->fd = util_file_open(part->path, &size, minsize, flags); if (part->fd == -1) { LOG(2, "failed to open file: %s", part->path); return -1; } /* check if filesize matches */ if (part->filesize != size) { ERR("file size does not match config: %s, %zu != %zu", part->path, size, part->filesize); errno = EINVAL; return -1; } } return 0; } /* * util_part_fdclose -- close part file */ void util_part_fdclose(struct pool_set_part *part) { LOG(3, "part %p", part); if (part->fd != -1) { (void) os_close(part->fd); part->fd = -1; } } /* * util_set_rpmem_attr -- (internal) overwrite existing pool attributes * * does not set uuid, next_part_uuid, prev_part_uuid */ static void util_set_rpmem_attr(struct pool_hdr *hdrp, const struct rpmem_pool_attr *rattr) { LOG(5, "hdrp %p rattr %p", hdrp, rattr); memcpy(hdrp->signature, rattr->signature, POOL_HDR_SIG_LEN); hdrp->major = rattr->major; hdrp->compat_features = rattr->compat_features; hdrp->incompat_features = rattr->incompat_features; hdrp->ro_compat_features = rattr->ro_compat_features; memcpy(hdrp->poolset_uuid, rattr->poolset_uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_repl_uuid, rattr->next_uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->prev_repl_uuid, rattr->prev_uuid, POOL_HDR_UUID_LEN); memcpy(&hdrp->arch_flags, rattr->user_flags, sizeof(struct arch_flags)); } /* * util_get_rpmem_attr -- (internal) get attributes for remote replica header */ static void util_get_rpmem_attr(struct rpmem_pool_attr *rattr, const struct pool_hdr *hdrp) { LOG(5, "rpmem_attr %p hdrp %p", rattr, hdrp); ASSERTne(rattr, NULL); memcpy(rattr->signature, hdrp->signature, POOL_HDR_SIG_LEN); rattr->major = hdrp->major; rattr->compat_features = hdrp->compat_features; rattr->incompat_features = hdrp->incompat_features; rattr->ro_compat_features = hdrp->ro_compat_features; memcpy(rattr->poolset_uuid, hdrp->poolset_uuid, POOL_HDR_UUID_LEN); memcpy(rattr->uuid, hdrp->uuid, POOL_HDR_UUID_LEN); memcpy(rattr->next_uuid, hdrp->next_repl_uuid, POOL_HDR_UUID_LEN); memcpy(rattr->prev_uuid, hdrp->prev_repl_uuid, POOL_HDR_UUID_LEN); memcpy(rattr->user_flags, &hdrp->arch_flags, sizeof(struct arch_flags)); } /* * util_remote_store_attr -- (internal) store attributes read from remote * replica in the local volatile pool header */ static void util_remote_store_attr(struct pool_hdr *hdrp, const struct rpmem_pool_attr *rattr) { LOG(4, "hdrp %p rpmem_attr %p", hdrp, rattr); util_set_rpmem_attr(hdrp, rattr); memcpy(hdrp->uuid, rattr->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_part_uuid, rattr->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->prev_part_uuid, rattr->uuid, POOL_HDR_UUID_LEN); } /* * util_update_remote_header -- update attributes of a remote replica; * the remote replica must be open */ int util_update_remote_header(struct pool_set *set, unsigned repn) { LOG(3, "set %p, repn %u", set, repn); ASSERTne(REP(set, repn)->remote, NULL); ASSERTne(REP(set, repn)->remote->rpp, NULL); struct pool_replica *rep = REP(set, repn); struct pool_hdr *hdr = HDR(rep, 0); /* get attributes from the local pool header */ struct rpmem_pool_attr attributes; util_get_rpmem_attr(&attributes, hdr); /* push the attributes to the remote replica */ RPMEMpool *rpp = rep->remote->rpp; int ret = Rpmem_set_attr(rpp, &attributes); if (ret) { ERR("!Rpmem_set_attr"); return -1; } return 0; } /* * util_pool_close_remote -- close a remote replica */ int util_pool_close_remote(RPMEMpool *rpp) { LOG(3, "rpp %p", rpp); return Rpmem_close(rpp); } /* * util_poolset_remote_open -- open or create a remote replica */ int util_poolset_remote_open(struct pool_replica *rep, unsigned repidx, size_t minsize, int create, void *pool_addr, size_t pool_size, unsigned *nlanes) { LOG(3, "rep %p repidx %u minsize %zu create %d " "pool_addr %p pool_size %zu nlanes %p", rep, repidx, minsize, create, pool_addr, pool_size, nlanes); ASSERTne(nlanes, NULL); if (!Rpmem_handle_remote) { return -1; } unsigned remote_nlanes = *nlanes; if (create) { struct rpmem_pool_attr rpmem_attr_create; util_get_rpmem_attr(&rpmem_attr_create, rep->part[0].hdr); rep->remote->rpp = Rpmem_create(rep->remote->node_addr, rep->remote->pool_desc, pool_addr, pool_size, &remote_nlanes, &rpmem_attr_create); if (rep->remote->rpp == NULL) { ERR("creating remote replica #%u failed", repidx); return -1; } rep->part[0].created = 1; } else { /* open */ struct rpmem_pool_attr rpmem_attr_open; rep->remote->rpp = Rpmem_open(rep->remote->node_addr, rep->remote->pool_desc, pool_addr, pool_size, &remote_nlanes, &rpmem_attr_open); if (rep->remote->rpp == NULL) { ERR("opening remote replica #%u failed", repidx); return -1; } util_remote_store_attr(rep->part[0].hdr, &rpmem_attr_open); } if (remote_nlanes < *nlanes) *nlanes = remote_nlanes; return 0; } /* * util_poolset_files_local -- (internal) open or create all the local * part files of a pool set and replica sets */ static int util_poolset_files_local(struct pool_set *set, size_t minpartsize, int create) { LOG(3, "set %p minpartsize %zu create %d", set, minpartsize, create); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; if (!rep->remote) { for (unsigned p = 0; p < rep->nparts; p++) { if (util_part_open(&rep->part[p], minpartsize, create)) return -1; } } } return 0; } /* * util_poolset_remote_replica_open -- open remote replica */ int util_poolset_remote_replica_open(struct pool_set *set, unsigned repidx, size_t minsize, int create, unsigned *nlanes) { #ifndef _WIN32 /* * This is a workaround for an issue with using device dax with * libibverbs. To handle fork() function calls correctly libfabric use * ibv_fork_init(3) which makes all registered memory being madvised * with MADV_DONTFORK flag. In libpmemobj the remote replication is * performed without pool header (first 4k). In such case the address * passed to madvise(2) is aligned to 4k, but device dax can require * different alignment (default is 2MB). This workaround madvises the * entire memory region before registering it by fi_mr_reg(3). * * The librpmem client requires fork() support to work correctly. */ if (set->replica[0]->part[0].is_dev_dax) { int ret = os_madvise(set->replica[0]->part[0].addr, set->replica[0]->part[0].filesize, MADV_DONTFORK); if (ret) { ERR("!madvise"); return ret; } } #endif void *pool_addr = (void *)((uintptr_t)set->replica[0]->part[0].addr); return util_poolset_remote_open(set->replica[repidx], repidx, minsize, create, pool_addr, set->poolsize, nlanes); } /* * util_poolset_files_remote -- (internal) open or create all the remote * part files of a pool set and replica sets */ static int util_poolset_files_remote(struct pool_set *set, size_t minsize, unsigned *nlanes, int create) { LOG(3, "set %p minsize %zu nlanes %p create %d", set, minsize, nlanes, create); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; if (rep->remote) { if (util_poolset_remote_replica_open(set, r, minsize, create, nlanes)) return -1; } } return 0; } /* * util_poolset_read -- read memory pool set file * * On success returns 0 and a pointer to a newly allocated structure * containing the info of all the parts of the pool set and replicas. */ int util_poolset_read(struct pool_set **setp, const char *path) { LOG(3, "setp %p path %s", setp, path); int oerrno; int ret = 0; int fd; if ((fd = os_open(path, O_RDONLY)) < 0) { ERR("!open: path \"%s\"", path); return -1; } ret = util_poolset_parse(setp, path, fd); oerrno = errno; (void) os_close(fd); errno = oerrno; return ret; } /* * util_poolset_create_set -- create a new pool set structure * * On success returns 0 and a pointer to a newly allocated structure * containing the info of all the parts of the pool set and replicas. */ int util_poolset_create_set(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, int ignore_sds) { LOG(3, "setp %p path %s poolsize %zu minsize %zu", setp, path, poolsize, minsize); int oerrno; int ret = 0; int fd; size_t size = 0; int is_dev_dax = util_file_is_device_dax(path); if (poolsize != 0) { if (is_dev_dax) { ERR("size must be zero for device dax"); return -1; } *setp = util_poolset_single(path, poolsize, 1, ignore_sds); if (*setp == NULL) return -1; return 0; } /* do not check minsize */ if ((fd = util_file_open(path, &size, 0, O_RDONLY)) == -1) return -1; char signature[POOLSET_HDR_SIG_LEN]; if (!is_dev_dax) { /* * read returns ssize_t, but we know it will return value * between -1 and POOLSET_HDR_SIG_LEN (11), so we can safely * cast it to int */ ret = (int)read(fd, signature, POOLSET_HDR_SIG_LEN); if (ret < 0) { ERR("!read %d", fd); goto err; } } if (is_dev_dax || ret < POOLSET_HDR_SIG_LEN || strncmp(signature, POOLSET_HDR_SIG, POOLSET_HDR_SIG_LEN)) { LOG(4, "not a pool set header"); (void) os_close(fd); if (size < minsize) { ERR("file is not a poolset file and its size (%zu)" " is smaller than %zu", size, minsize); errno = EINVAL; return -1; } *setp = util_poolset_single(path, size, 0, ignore_sds); if (*setp == NULL) return -1; return 0; } ret = util_poolset_parse(setp, path, fd); if (ret) goto err; (*setp)->ignore_sds = ignore_sds; #ifdef _WIN32 /* remote replication is not supported on Windows */ if ((*setp)->remote) { util_poolset_free(*setp); ERR("remote replication is not supported on Windows"); errno = ENOTSUP; ret = -1; goto err; } #endif /* _WIN32 */ err: oerrno = errno; (void) os_close(fd); errno = oerrno; return ret; } /* * util_poolset_check_header_options -- (internal) check if poolset options * match given flags */ static int util_poolset_check_header_options(struct pool_set *set, uint32_t incompat) { LOG(3, "set %p, incompat %#x", set, incompat); if (((set->options & OPTION_SINGLEHDR) == 0) != ((incompat & POOL_FEAT_SINGLEHDR) == 0)) { ERR( "poolset file options (%u) do not match incompat feature flags (%#x)", set->options, incompat); errno = EINVAL; return -1; } return 0; } /* * util_header_create -- create header of a single pool set file */ int util_header_create(struct pool_set *set, unsigned repidx, unsigned partidx, const struct pool_attr *attr, int overwrite) { LOG(3, "set %p repidx %u partidx %u attr %p overwrite %d", set, repidx, partidx, attr, overwrite); ASSERTne(attr, NULL); struct pool_replica *rep = set->replica[repidx]; /* opaque info lives at the beginning of mapped memory pool */ struct pool_hdr *hdrp = rep->part[partidx].hdr; /* check if the pool header is all zeros */ if (!util_is_zeroed(hdrp, sizeof(*hdrp)) && !overwrite) { ERR("Non-empty file detected"); errno = EEXIST; return -1; } /* create pool's header */ util_pool_attr2hdr(hdrp, attr); if (set->options & OPTION_SINGLEHDR) hdrp->incompat_features |= POOL_FEAT_SINGLEHDR; memcpy(hdrp->poolset_uuid, set->uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->uuid, PART(rep, partidx).uuid, POOL_HDR_UUID_LEN); /* link parts */ if (set->options & OPTION_SINGLEHDR) { /* next/prev part point to part #0 */ ASSERTeq(partidx, 0); memcpy(hdrp->prev_part_uuid, PART(rep, 0).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_part_uuid, PART(rep, 0).uuid, POOL_HDR_UUID_LEN); } else { memcpy(hdrp->prev_part_uuid, PARTP(rep, partidx).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_part_uuid, PARTN(rep, partidx).uuid, POOL_HDR_UUID_LEN); } /* link replicas */ if (!util_is_zeroed(attr->prev_repl_uuid, POOL_HDR_UUID_LEN)) { memcpy(hdrp->prev_repl_uuid, attr->prev_repl_uuid, POOL_HDR_UUID_LEN); } else { memcpy(hdrp->prev_repl_uuid, PART(REPP(set, repidx), 0).uuid, POOL_HDR_UUID_LEN); } if (!util_is_zeroed(attr->next_repl_uuid, POOL_HDR_UUID_LEN)) { memcpy(hdrp->next_repl_uuid, attr->next_repl_uuid, POOL_HDR_UUID_LEN); } else { memcpy(hdrp->next_repl_uuid, PART(REPN(set, repidx), 0).uuid, POOL_HDR_UUID_LEN); } if (!rep->remote) { os_stat_t stbuf; if (os_fstat(rep->part[partidx].fd, &stbuf) != 0) { ERR("!fstat"); return -1; } ASSERT(stbuf.st_ctime); hdrp->crtime = (uint64_t)stbuf.st_ctime; } int arch_is_zeroed = util_is_zeroed(attr->arch_flags, POOL_HDR_ARCH_LEN); if (arch_is_zeroed) util_get_arch_flags(&hdrp->arch_flags); util_convert2le_hdr(hdrp); if (!arch_is_zeroed) { memcpy(&hdrp->arch_flags, attr->arch_flags, POOL_HDR_ARCH_LEN); } if (!set->ignore_sds && partidx == 0 && !rep->remote) { shutdown_state_init(&hdrp->sds, &PART(rep, 0)); for (unsigned p = 0; p < rep->nparts; p++) { if (shutdown_state_add_part(&hdrp->sds, PART(rep, p).path, &PART(rep, 0))) return -1; } shutdown_state_set_flag(&hdrp->sds, &PART(rep, 0)); } util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 1, POOL_HDR_CSUM_END_OFF); /* store pool's header */ util_persist_auto(rep->is_pmem, hdrp, sizeof(*hdrp)); return 0; } /* * util_header_check -- (internal) validate header of a single pool set file */ static int util_header_check(struct pool_set *set, unsigned repidx, unsigned partidx, const struct pool_attr *attr) { LOG(3, "set %p repidx %u partidx %u attr %p", set, repidx, partidx, attr); ASSERTne(attr, NULL); struct pool_replica *rep = set->replica[repidx]; /* opaque info lives at the beginning of mapped memory pool */ struct pool_hdr *hdrp = rep->part[partidx].hdr; struct pool_hdr hdr; memcpy(&hdr, hdrp, sizeof(hdr)); /* local copy of a remote header does not need to be converted */ if (rep->remote == NULL) util_convert2h_hdr_nocheck(&hdr); /* to be valid, a header must have a major version of at least 1 */ if (hdr.major == 0) { ERR("invalid major version (0)"); errno = EINVAL; return -1; } /* check signature */ if (memcmp(hdr.signature, attr->signature, POOL_HDR_SIG_LEN)) { ERR("wrong pool type: \"%.8s\"", hdr.signature); errno = EINVAL; return -1; } /* check format version number */ if (hdr.major != attr->major) { ERR("pool version %d (library expects %d)", hdr.major, attr->major); if (hdr.major < attr->major) { ERR("Please run the pmempool convert utility to " "upgrade the pool."); } errno = EINVAL; return -1; } rep->part[partidx].rdonly = 0; int retval = util_feature_check(&hdr, attr->incompat_features, attr->ro_compat_features, attr->compat_features); if (retval < 0) return -1; if (retval == 0) rep->part[partidx].rdonly = 1; if (rep->remote == NULL) { /* * and to be valid, the fields must checksum correctly * * NOTE: checksum validation is performed after format version * and feature check, because if POOL_FEAT_CKSUM_2K flag is set, * we want to report it as incompatible feature, rather than * invalid checksum. */ if (!util_checksum(&hdr, sizeof(hdr), &hdr.checksum, 0, POOL_HDR_CSUM_END_OFF)) { ERR("invalid checksum of pool header"); errno = EINVAL; return -1; } LOG(3, "valid header, signature \"%.8s\"", hdr.signature); } if (util_check_arch_flags(&hdr.arch_flags)) { ERR("wrong architecture flags"); errno = EINVAL; return -1; } /* check pool set UUID */ if (memcmp(HDR(REP(set, 0), 0)->poolset_uuid, hdr.poolset_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong pool set UUID"); errno = EINVAL; return -1; } /* check pool set linkage */ if (memcmp(HDRP(rep, partidx)->uuid, hdr.prev_part_uuid, POOL_HDR_UUID_LEN) || memcmp(HDRN(rep, partidx)->uuid, hdr.next_part_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong part UUID"); errno = EINVAL; return -1; } /* check format version */ if (HDR(rep, 0)->major != hdrp->major) { ERR("incompatible pool format"); errno = EINVAL; return -1; } /* check compatibility features */ if (HDR(rep, 0)->compat_features != hdrp->compat_features || HDR(rep, 0)->incompat_features != hdrp->incompat_features || HDR(rep, 0)->ro_compat_features != hdrp->ro_compat_features) { ERR("incompatible feature flags"); errno = EINVAL; return -1; } /* check poolset options */ if (util_poolset_check_header_options(set, HDR(rep, 0)->incompat_features)) return -1; return 0; } /* * util_header_check_remote -- (internal) validate header of a remote * pool set file */ static int util_header_check_remote(struct pool_set *set, unsigned partidx) { LOG(3, "set %p partidx %u ", set, partidx); /* there is only one replica in remote poolset */ struct pool_replica *rep = set->replica[0]; /* opaque info lives at the beginning of mapped memory pool */ struct pool_hdr *hdrp = rep->part[partidx].hdr; struct pool_hdr hdr; if (util_is_zeroed(hdrp, sizeof(*hdrp))) { ERR("pool header zeroed"); errno = EINVAL; return -1; } memcpy(&hdr, hdrp, sizeof(hdr)); util_convert2h_hdr_nocheck(&hdr); /* valid header found */ if (memcmp(HDR(rep, 0)->signature, hdrp->signature, POOL_HDR_SIG_LEN)) { ERR("pool signature mismatch in part %d", partidx); errno = EINVAL; return -1; } /* check format version */ if (HDR(rep, 0)->major != hdrp->major) { ERR("pool version mismatch in part %d", partidx); errno = EINVAL; return -1; } /* check compatibility features */ if (HDR(rep, 0)->compat_features != hdrp->compat_features) { ERR("'may have' compatibility flags mismatch in part %d", partidx); errno = EINVAL; return -1; } if (HDR(rep, 0)->incompat_features != hdrp->incompat_features) { ERR("'must support' compatibility flags mismatch in part %d", partidx); errno = EINVAL; return -1; } if (HDR(rep, 0)->ro_compat_features != hdrp->ro_compat_features) { ERR("'force read-only' compatibility flags mismatch in part %d", partidx); errno = EINVAL; return -1; } /* * and to be valid, the fields must checksum correctly * * NOTE: checksum validation is performed after format version and * feature check, because if POOL_FEAT_CKSUM_2K flag is set, * we want to report it as incompatible feature, rather than invalid * checksum. */ if (!util_checksum(&hdr, sizeof(hdr), &hdr.checksum, 0, POOL_HDR_CSUM_END_OFF)) { ERR("invalid checksum of pool header"); return -1; } LOG(3, "valid header, signature \"%.8s\"", hdr.signature); /* check pool set UUID */ if (memcmp(HDR(rep, 0)->poolset_uuid, hdrp->poolset_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong pool set UUID in part %d", partidx); errno = EINVAL; return -1; } /* check previous replica UUID */ if (memcmp(HDR(rep, 0)->prev_repl_uuid, hdrp->prev_repl_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong previous replica UUID in part %d", partidx); errno = EINVAL; return -1; } /* check next replica UUID */ if (memcmp(HDR(rep, 0)->next_repl_uuid, hdrp->next_repl_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong next replica UUID in part %d", partidx); errno = EINVAL; return -1; } if (memcmp(&HDR(rep, 0)->arch_flags, &hdrp->arch_flags, sizeof(hdrp->arch_flags))) { ERR("wrong architecture flags"); errno = EINVAL; return -1; } /* check pool set linkage */ if (memcmp(HDRP(rep, partidx)->uuid, hdrp->prev_part_uuid, POOL_HDR_UUID_LEN) || memcmp(HDRN(rep, partidx)->uuid, hdrp->next_part_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong part UUID in part %d", partidx); errno = EINVAL; return -1; } if (!set->ignore_sds && partidx == 0) { struct shutdown_state sds; shutdown_state_init(&sds, NULL); for (unsigned p = 0; p < rep->nparts; p++) { if (shutdown_state_add_part(&sds, PART(rep, p).path, NULL)) return -1; } if (shutdown_state_check(&sds, &hdrp->sds, &PART(rep, 0))) { errno = EINVAL; return -1; } shutdown_state_set_flag(&hdrp->sds, &PART(rep, 0)); } rep->part[partidx].rdonly = 0; return 0; } /* * util_replica_set_is_pmem -- sets per-replica is_pmem flag * * The replica is PMEM if: * - all parts are on device dax, or * - all parts are mapped with MAP_SYNC. * * It's enough to check only first part because it's already verified * that either all or none parts are device dax or mapped with MAP_SYNC. */ static inline void util_replica_set_is_pmem(struct pool_replica *rep) { rep->is_pmem = rep->part[0].is_dev_dax || rep->part[0].map_sync || pmem_is_pmem(rep->part[0].addr, rep->resvsize); } /* * util_replica_map_local -- (internal) map memory pool for local replica */ static int util_replica_map_local(struct pool_set *set, unsigned repidx, int flags) { LOG(3, "set %p repidx %u flags %d", set, repidx, flags); /* * XXX: Like we reserve space for all parts in this replica when we map * the first part, we need to reserve the space for all replicas * upfront. It is not necessary that the replicas are contiguous but * that way we would not fragment the memory much. I think we should * leave this to MM, but let's have a note as per our collective minds. */ #ifndef _WIN32 int remaining_retries = 0; #else int remaining_retries = 10; #endif int retry_for_contiguous_addr; size_t mapsize; /* header size for all headers but the first one */ size_t hdrsize = (set->options & (OPTION_SINGLEHDR | OPTION_NOHDRS)) ? 0 : Mmap_align; void *addr; struct pool_replica *rep = set->replica[repidx]; ASSERTeq(rep->remote, NULL); ASSERTne(rep->part, NULL); do { retry_for_contiguous_addr = 0; mapsize = rep->part[0].filesize & ~(Mmap_align - 1); /* determine a hint address for mmap() */ addr = util_map_hint(rep->resvsize, 0); if (addr == MAP_FAILED) { ERR("cannot find a contiguous region of given size"); return -1; } /* map the first part and reserve space for remaining parts */ if (util_map_part(&rep->part[0], addr, rep->resvsize, 0, flags, 0) != 0) { LOG(2, "pool mapping failed - replica #%u part #0", repidx); return -1; } VALGRIND_REGISTER_PMEM_MAPPING(rep->part[0].addr, rep->part[0].size); VALGRIND_REGISTER_PMEM_FILE(rep->part[0].fd, rep->part[0].addr, rep->part[0].size, 0); set->zeroed &= rep->part[0].created; addr = (char *)rep->part[0].addr + mapsize; /* * map the remaining parts of the usable pool space * (aligned to memory mapping granularity) */ for (unsigned p = 1; p < rep->nparts; p++) { /* map data part */ if (util_map_part(&rep->part[p], addr, 0, hdrsize, flags | MAP_FIXED, 0) != 0) { /* * if we can't map the part at the address we * asked for, unmap all the parts that are * mapped and remap at a different address. */ if ((errno == EINVAL) && (remaining_retries > 0)) { LOG(2, "usable space mapping failed - " "part #%d - retrying", p); retry_for_contiguous_addr = 1; remaining_retries--; util_unmap_parts(rep, 0, p - 1); /* release rest of the VA reserved */ ASSERTne(addr, NULL); ASSERTne(addr, MAP_FAILED); munmap(addr, rep->resvsize - mapsize); break; } LOG(2, "usable space mapping failed - part #%d", p); goto err; } VALGRIND_REGISTER_PMEM_FILE(rep->part[p].fd, rep->part[p].addr, rep->part[p].size, hdrsize); mapsize += rep->part[p].size; set->zeroed &= rep->part[p].created; addr = (char *)addr + rep->part[p].size; } } while (retry_for_contiguous_addr); /* * Initially part[0].size is the size of address space * reservation for all parts from given replica. After * mapping that space we need to overwrite part[0].size * with its actual size to be consistent - size for each * part should be the actual mapping size of this part * only - it simplifies future calculations. */ rep->part[0].size = rep->part[0].filesize & ~(Mmap_align - 1); if (util_replica_check_map_sync(set, repidx, 0)) goto err; util_replica_set_is_pmem(rep); if (Prefault_at_create) util_replica_force_page_allocation(rep); ASSERTeq(mapsize, rep->repsize); LOG(3, "replica #%u addr %p", repidx, rep->part[0].addr); return 0; err: LOG(4, "error clean up"); int oerrno = errno; if (mapsize < rep->repsize) { ASSERTne(rep->part[0].addr, NULL); ASSERTne(rep->part[0].addr, MAP_FAILED); munmap(rep->part[0].addr, rep->resvsize - mapsize); } for (unsigned p = 0; p < rep->nparts; p++) { util_unmap_part(&rep->part[p]); } errno = oerrno; return -1; } /* * util_replica_init_headers_local -- (internal) initialize pool headers */ static int util_replica_init_headers_local(struct pool_set *set, unsigned repidx, int flags, const struct pool_attr *attr) { LOG(3, "set %p repidx %u flags %d attr %p", set, repidx, flags, attr); struct pool_replica *rep = set->replica[repidx]; /* map all headers - don't care about the address */ for (unsigned p = 0; p < rep->nhdrs; p++) { if (util_map_hdr(&rep->part[p], flags, 0) != 0) { LOG(2, "header mapping failed - part #%d", p); goto err; } } /* create headers, set UUID's */ for (unsigned p = 0; p < rep->nhdrs; p++) { if (util_header_create(set, repidx, p, attr, 0) != 0) { LOG(2, "header creation failed - part #%d", p); goto err; } } /* unmap all headers */ for (unsigned p = 0; p < rep->nhdrs; p++) util_unmap_hdr(&rep->part[p]); return 0; err: LOG(4, "error clean up"); int oerrno = errno; for (unsigned p = 0; p < rep->nhdrs; p++) { util_unmap_hdr(&rep->part[p]); } errno = oerrno; return -1; } /* * util_replica_create_local -- (internal) create a new memory pool for local * replica */ static int util_replica_create_local(struct pool_set *set, unsigned repidx, int flags, const struct pool_attr *attr) { LOG(3, "set %p repidx %u flags %d attr %p", set, repidx, flags, attr); /* * the first replica has to be mapped prior to remote ones so if * a replica is already mapped skip mapping creation */ if (PART(REP(set, repidx), 0).addr == NULL) { if (util_replica_map_local(set, repidx, flags) != 0) { LOG(2, "replica #%u map failed", repidx); return -1; } } if (attr == NULL) return 0; if (util_replica_init_headers_local(set, repidx, flags, attr) != 0) { LOG(2, "replica #%u headers initialization failed", repidx); return -1; } return 0; } /* * util_replica_create_remote -- (internal) create a new memory pool * for remote replica */ static int util_replica_create_remote(struct pool_set *set, unsigned repidx, int flags, const struct pool_attr *attr) { LOG(3, "set %p repidx %u flags %d attr %p", set, repidx, flags, attr); struct pool_replica *rep = set->replica[repidx]; ASSERTne(rep->remote, NULL); ASSERTne(rep->part, NULL); ASSERTeq(rep->nparts, 1); ASSERTeq(rep->nhdrs, 1); ASSERTne(attr, NULL); struct pool_set_part *part = rep->part; /* * A remote replica has one fake part of size equal twice pool header * size for storing pool header and pool descriptor. */ part->size = rep->repsize; ASSERT(IS_PAGE_ALIGNED(part->size)); part->remote_hdr = Zalloc(part->size + Pagesize); if (!part->remote_hdr) { ERR("!Zalloc"); return -1; } part->hdr = PAGE_ALIGN_UP(part->remote_hdr); part->addr = PAGE_ALIGN_UP(part->remote_hdr); part->hdrsize = POOL_HDR_SIZE; /* create header, set UUID's */ if (util_header_create(set, repidx, 0, attr, 0) != 0) { LOG(2, "header creation failed - part #0"); Free(part->remote_hdr); return -1; } LOG(3, "replica #%u addr %p", repidx, rep->part[0].addr); return 0; } /* * util_replica_close -- close a memory pool replica * * This function unmaps all mapped memory regions. */ int util_replica_close(struct pool_set *set, unsigned repidx) { LOG(3, "set %p repidx %u", set, repidx); struct pool_replica *rep = set->replica[repidx]; if (rep->remote == NULL) { struct pool_set_part *part = &PART(rep, 0); if (!set->ignore_sds && part->addr != NULL && part->size != 0) { /* XXX: DEEP DRAIN */ struct pool_hdr *hdr = part->addr; RANGE_RW(hdr, sizeof(*hdr), part->is_dev_dax); shutdown_state_clear_flag(&hdr->sds, part); } for (unsigned p = 0; p < rep->nhdrs; p++) util_unmap_hdr(&rep->part[p]); rep->part[0].size = rep->resvsize; util_unmap_part(&rep->part[0]); } else { LOG(4, "freeing volatile header of remote replica #%u", repidx); Free(rep->part[0].remote_hdr); rep->part[0].remote_hdr = NULL; rep->part[0].hdr = NULL; rep->part[0].hdrsize = 0; rep->part[0].addr = NULL; rep->part[0].size = 0; } return 0; } /* * util_poolset_append_new_part -- (internal) creates a new part in each replica * of the poolset */ static int util_poolset_append_new_part(struct pool_set *set, size_t size) { LOG(3, "set %p size %zu", set, size); if (!set->directory_based) return -1; struct pool_set_directory *d; size_t directory_id; char *path; size_t path_len; unsigned r; for (r = 0; r < set->nreplicas; ++r) { struct pool_replica *rep = set->replica[r]; directory_id = set->next_directory_id % VEC_SIZE(&rep->directory); d = VEC_GET(&rep->directory, directory_id); path_len = strlen(d->path) + PMEM_FILE_MAX_LEN; if ((path = Malloc(path_len)) == NULL) { ERR("!Malloc"); goto err_part_init; } snprintf(path, path_len, "%s" OS_DIR_SEP_STR "%0*u%s", d->path, PMEM_FILE_PADDING, set->next_id, PMEM_EXT); if (util_replica_add_part(&set->replica[r], path, size) != 0) FATAL("cannot add a new part to the replica info"); } set->next_directory_id += 1; set->next_id += 1; util_poolset_set_size(set); return 0; err_part_init: /* for each replica 0..r-1 remove the last part */ for (unsigned rn = 0; rn < r; ++rn) { struct pool_replica *rep = set->replica[rn]; unsigned pidx = rep->nparts - 1; Free((void *)(rep->part[pidx].path)); rep->part[pidx].path = NULL; rep->nparts--; } return -1; } /* * util_pool_extend -- extends the poolset by the provided size */ void * util_pool_extend(struct pool_set *set, size_t *size, size_t minpartsize) { LOG(3, "set %p size %zu minpartsize %zu", set, *size, minpartsize); if (*size == 0) { ERR("cannot extend pool by 0 bytes"); return NULL; } if ((set->options & OPTION_SINGLEHDR) == 0) { ERR( "extending the pool by appending parts with headers is not supported!"); return NULL; } if (set->poolsize + *size > set->resvsize) { *size = set->resvsize - set->poolsize; if (*size < minpartsize) { ERR("exceeded reservation size"); return NULL; } LOG(4, "extend size adjusted to not exceed reservation size"); } size_t old_poolsize = set->poolsize; if (util_poolset_append_new_part(set, *size) != 0) { ERR("unable to append a new part to the pool"); return NULL; } size_t hdrsize = (set->options & OPTION_SINGLEHDR) ? 0 : Mmap_align; void *addr = NULL; void *addr_base = NULL; unsigned r; for (r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; unsigned pidx = rep->nparts - 1; struct pool_set_part *p = &rep->part[pidx]; if (util_part_open(p, 0, 1 /* create */) != 0) { ERR("cannot open the new part"); goto err; } addr = (char *)rep->part[0].addr + old_poolsize; if (addr_base == NULL) addr_base = addr; if (util_map_part(p, addr, 0, hdrsize, MAP_SHARED | MAP_FIXED, 0) != 0) { ERR("cannot map the new part"); goto err; } /* * new part must be mapped the same way as all the rest * within a replica */ if (p->map_sync != rep->part[0].map_sync) { if (p->map_sync) ERR("new part cannot be mapped with MAP_SYNC"); else ERR("new part mapped with MAP_SYNC"); goto err; } } /* XXX: mode should be the same as for pmemxxx_create() */ if (util_poolset_chmod(set, S_IWUSR | S_IRUSR)) goto err; util_poolset_fdclose(set); return addr_base; err: for (unsigned rn = 0; rn <= r; ++rn) { struct pool_replica *rep = set->replica[r]; unsigned pidx = rep->nparts - 1; struct pool_set_part *p = &rep->part[pidx]; rep->nparts--; if (p->fd != 0) (void) os_close(p->fd); if (p->created) os_unlink(p->path); Free((void *)p->path); p->path = NULL; } util_poolset_set_size(set); return NULL; } /* * util_pool_create_uuids -- create a new memory pool (set or a single file) * with given uuids * * On success returns 0 and a pointer to a newly allocated structure * containing the info of all the parts of the pool set and replicas. */ int util_pool_create_uuids(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, size_t minpartsize, const struct pool_attr *attr, unsigned *nlanes, int can_have_rep, int remote) { LOG(3, "setp %p path %s poolsize %zu minsize %zu minpartsize %zu " "pattr %p nlanes %p can_have_rep %i remote %i", setp, path, poolsize, minsize, minpartsize, attr, nlanes, can_have_rep, remote); /* attributes cannot be NULL for local replicas */ ASSERT(remote || attr != NULL); int flags = MAP_SHARED; int oerrno; /* check if file exists */ if (poolsize > 0 && os_access(path, F_OK) == 0) { ERR("file %s already exists", path); errno = EEXIST; return -1; } int ret = util_poolset_create_set(setp, path, poolsize, minsize, 0); if (ret < 0) { LOG(2, "cannot create pool set -- '%s'", path); return -1; } struct pool_set *set = *setp; ASSERT(set->nreplicas > 0); if (!remote && (set->options & OPTION_NOHDRS)) { ERR( "the NOHDRS poolset option is not supported for local poolsets"); util_poolset_free(set); errno = EINVAL; return -1; } if ((attr == NULL) != ((set->options & OPTION_NOHDRS) != 0)) { ERR( "pool attributes are not supported for poolsets without headers (with the NOHDRS option)"); util_poolset_free(set); errno = EINVAL; return -1; } if (set->directory_based && ((set->options & OPTION_SINGLEHDR) == 0)) { ERR( "directory based pools are not supported for poolsets with headers (without SINGLEHDR option)"); util_poolset_free(set); errno = EINVAL; return -1; } if (set->resvsize < minsize) { ERR("reservation pool size %zu smaller than %zu", set->resvsize, minsize); util_poolset_free(set); errno = EINVAL; return -1; } if (set->directory_based && set->poolsize == 0 && util_poolset_append_new_part(set, minsize) != 0) { ERR("cannot create a new part in provided directories"); util_poolset_free(set); return -1; } if (set->poolsize < minsize) { ERR("net pool size %zu smaller than %zu", set->poolsize, minsize); util_poolset_free(set); errno = EINVAL; return -1; } if (remote) { /* it is a remote replica - it cannot have replicas */ if (set->nreplicas > 1) { LOG(2, "remote pool set cannot have replicas"); util_poolset_free(set); errno = EINVAL; return -1; } /* check if poolset options match remote pool attributes */ if (attr != NULL && ((set->options & OPTION_SINGLEHDR) == 0) != ((attr->incompat_features & POOL_FEAT_SINGLEHDR) == 0)) { ERR( "pool incompat feature flags and remote poolset options do not match"); errno = EINVAL; return -1; } } if (!can_have_rep && set->nreplicas > 1) { ERR("replication not supported"); util_poolset_free(set); errno = ENOTSUP; return -1; } if (set->remote && util_remote_load()) { ERR( "the pool set requires a remote replica, but the '%s' library cannot be loaded", LIBRARY_REMOTE); util_poolset_free(set); return -1; } set->zeroed = 1; if (attr != NULL) { if (!util_is_zeroed(attr->poolset_uuid, POOL_HDR_UUID_LEN)) { memcpy(set->uuid, attr->poolset_uuid, POOL_HDR_UUID_LEN); } else { /* generate pool set UUID */ ret = util_uuid_generate(set->uuid); if (ret < 0) { LOG(2, "cannot generate pool set UUID"); goto err_poolset; } } /* generate UUID's for all the parts */ for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned i = 0; i < rep->nhdrs; i++) { ret = util_uuid_generate(rep->part[i].uuid); if (ret < 0) { LOG(2, "cannot generate pool set part UUID"); goto err_poolset; } } } /* overwrite UUID of the first part if given */ if (!util_is_zeroed(attr->first_part_uuid, POOL_HDR_UUID_LEN)) { memcpy(set->replica[0]->part[0].uuid, attr->first_part_uuid, POOL_HDR_UUID_LEN); } } ret = util_poolset_files_local(set, minpartsize, 1); if (ret != 0) goto err_poolset; /* map first local replica - it has to exist prior to remote ones */ ret = util_replica_map_local(set, 0, flags); if (ret != 0) goto err_poolset; /* prepare remote replicas first */ if (set->remote) { for (unsigned r = 0; r < set->nreplicas; r++) { if (REP(set, r)->remote == NULL) { continue; } if (util_replica_create_remote(set, r, flags, attr) != 0) { LOG(2, "replica #%u creation failed", r); goto err_create; } } ret = util_poolset_files_remote(set, minsize, nlanes, 1 /* create */); if (ret != 0) goto err_create; } /* prepare local replicas */ if (remote) { if (util_replica_create_local(set, 0, flags, attr) != 0) { LOG(2, "replica #0 creation failed"); goto err_create; } } else { for (unsigned r = 0; r < set->nreplicas; r++) { if (REP(set, r)->remote != NULL) { continue; } if (util_replica_create_local(set, r, flags, attr) != 0) { LOG(2, "replica #%u creation failed", r); goto err_create; } } } return 0; err_create: oerrno = errno; for (unsigned r = 0; r < set->nreplicas; r++) util_replica_close(set, r); errno = oerrno; err_poolset: oerrno = errno; util_poolset_close(set, DELETE_CREATED_PARTS); errno = oerrno; return -1; } /* * util_pool_create -- create a new memory pool (set or a single file) * * On success returns 0 and a pointer to a newly allocated structure * containing the info of all the parts of the pool set and replicas. */ int util_pool_create(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, size_t minpartsize, const struct pool_attr *attr, unsigned *nlanes, int can_have_rep) { LOG(3, "setp %p path %s poolsize %zu minsize %zu minpartsize %zu " "attr %p nlanes %p can_have_rep %i", setp, path, poolsize, minsize, minpartsize, attr, nlanes, can_have_rep); return util_pool_create_uuids(setp, path, poolsize, minsize, minpartsize, attr, nlanes, can_have_rep, POOL_LOCAL); } /* * util_replica_open_local -- (internal) open a memory pool local replica */ static int util_replica_open_local(struct pool_set *set, unsigned repidx, int flags) { LOG(3, "set %p repidx %u flags %d", set, repidx, flags); int remaining_retries = 10; int retry_for_contiguous_addr; size_t mapsize; size_t hdrsize = (set->options & (OPTION_SINGLEHDR | OPTION_NOHDRS)) ? 0 : Mmap_align; struct pool_replica *rep = set->replica[repidx]; void *addr = rep->mapaddr; /* mapaddr can be set for master replica only */ ASSERT(repidx == 0 || addr == NULL); do { retry_for_contiguous_addr = 0; /* determine a hint address for mmap() if not specified */ if (addr == NULL) addr = util_map_hint(rep->resvsize, 0); if (addr == MAP_FAILED) { ERR("cannot find a contiguous region of given size"); return -1; } mapsize = rep->part[0].filesize & ~(Mmap_align - 1); /* map the first part and reserve space for remaining parts */ if (util_map_part(&rep->part[0], addr, rep->resvsize, 0, flags, 0) != 0) { LOG(2, "pool mapping failed - replica #%u part #0", repidx); return -1; } VALGRIND_REGISTER_PMEM_MAPPING(rep->part[0].addr, rep->resvsize); VALGRIND_REGISTER_PMEM_FILE(rep->part[0].fd, rep->part[0].addr, rep->resvsize, 0); /* map all headers - don't care about the address */ for (unsigned p = 0; p < rep->nhdrs; p++) { if (util_map_hdr(&rep->part[p], flags, 0) != 0) { LOG(2, "header mapping failed - part #%d", p); goto err; } } addr = (char *)rep->part[0].addr + mapsize; /* * map the remaining parts of the usable pool space * (aligned to memory mapping granularity) */ for (unsigned p = 1; p < rep->nparts; p++) { /* map data part */ if (util_map_part(&rep->part[p], addr, 0, hdrsize, flags | MAP_FIXED, 0) != 0) { /* * if we can't map the part at the address we * asked for, unmap all the parts that are * mapped and remap at a different address. */ if ((errno == EINVAL) && (remaining_retries > 0)) { LOG(2, "usable space mapping failed - " "part #%d - retrying", p); retry_for_contiguous_addr = 1; remaining_retries--; util_unmap_parts(rep, 0, p - 1); /* release rest of the VA reserved */ munmap(rep->part[0].addr, rep->resvsize); break; } LOG(2, "usable space mapping failed - part #%d", p); goto err; } VALGRIND_REGISTER_PMEM_FILE(rep->part[p].fd, rep->part[p].addr, rep->part[p].size, hdrsize); mapsize += rep->part[p].size; addr = (char *)addr + rep->part[p].size; } } while (retry_for_contiguous_addr); /* * Initially part[0].size is the size of address space * reservation for all parts from given replica. After * mapping that space we need to overwrite part[0].size * with its actual size to be consistent - size for each * part should be the actual mapping size of this part * only - it simplifies future calculations. */ rep->part[0].size = rep->part[0].filesize & ~(Mmap_align - 1); if (util_replica_check_map_sync(set, repidx, 1)) goto err; util_replica_set_is_pmem(rep); if (Prefault_at_open) util_replica_force_page_allocation(rep); ASSERTeq(mapsize, rep->repsize); /* calculate pool size - choose the smallest replica size */ if (rep->repsize < set->poolsize) set->poolsize = rep->repsize; LOG(3, "replica addr %p", rep->part[0].addr); return 0; err: LOG(4, "error clean up"); int oerrno = errno; if (mapsize < rep->repsize) { ASSERTne(rep->part[0].addr, NULL); ASSERTne(rep->part[0].addr, MAP_FAILED); munmap(rep->part[0].addr, rep->resvsize - mapsize); } for (unsigned p = 0; p < rep->nhdrs; p++) util_unmap_hdr(&rep->part[p]); for (unsigned p = 0; p < rep->nparts; p++) util_unmap_part(&rep->part[p]); errno = oerrno; return -1; } /* * util_replica_open_remote -- open a memory pool for remote replica */ int util_replica_open_remote(struct pool_set *set, unsigned repidx, int flags) { LOG(3, "set %p repidx %u flags %d", set, repidx, flags); struct pool_replica *rep = set->replica[repidx]; ASSERTne(rep->remote, NULL); ASSERTne(rep->part, NULL); ASSERTeq(rep->nparts, 1); ASSERTeq(rep->nhdrs, 1); struct pool_set_part *part = rep->part; part->size = rep->repsize; ASSERT(IS_PAGE_ALIGNED(part->size)); part->remote_hdr = Zalloc(part->size + Pagesize); if (!part->remote_hdr) { ERR("!Zalloc"); return -1; } part->hdr = PAGE_ALIGN_UP(part->remote_hdr); part->addr = PAGE_ALIGN_UP(part->remote_hdr); part->hdrsize = POOL_HDR_SIZE; LOG(3, "replica #%u addr %p", repidx, rep->part[0].addr); return 0; } /* * util_replica_open -- open a memory pool replica */ int util_replica_open(struct pool_set *set, unsigned repidx, int flags) { LOG(3, "set %p repidx %u flags %d", set, repidx, flags); if (set->replica[repidx]->remote) return util_replica_open_remote(set, repidx, flags); return util_replica_open_local(set, repidx, flags); } /* * util_replica_set_attr -- overwrite existing replica attributes */ int util_replica_set_attr(struct pool_replica *rep, const struct rpmem_pool_attr *rattr) { LOG(3, "rep %p, rattr %p", rep, rattr); ASSERT(rattr != NULL || rep->nhdrs == 0); if (rattr != NULL && rep->nhdrs == 0) { ERR( "cannot set pool attributes for a replica without headers (with the NOHDRS option)"); errno = EINVAL; return -1; } int flags = MAP_SHARED; /* map all headers - don't care about the address */ for (unsigned p = 0; p < rep->nparts; p++) { if (util_map_hdr(&rep->part[p], flags, 0) != 0) { LOG(2, "header mapping failed - part #%d", p); goto err; } } for (unsigned p = 0; p < rep->nhdrs; p++) { ASSERTne(rattr, NULL); struct pool_hdr *hdrp = HDR(rep, p); ASSERTne(hdrp, NULL); util_convert2h_hdr_nocheck(hdrp); util_set_rpmem_attr(hdrp, rattr); if (hdrp == HDR(rep, 0)) memcpy(hdrp->uuid, rattr->uuid, POOL_HDR_UUID_LEN); if (hdrp == HDRP(rep, 0)) memcpy(hdrp->next_part_uuid, rattr->uuid, POOL_HDR_UUID_LEN); if (hdrp == HDRN(rep, 0)) memcpy(hdrp->prev_part_uuid, rattr->uuid, POOL_HDR_UUID_LEN); util_convert2le_hdr(hdrp); util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 1, POOL_HDR_CSUM_END_OFF); /* store pool's header */ util_persist_auto(rep->is_pmem, hdrp, sizeof(*hdrp)); } /* unmap all headers */ for (unsigned p = 0; p < rep->nhdrs; p++) util_unmap_hdr(&rep->part[p]); return 0; err: for (unsigned p = 0; p < rep->nhdrs; p++) { util_unmap_hdr(&rep->part[p]); } return -1; } /* * util_get_attr_from_header -- get pool attributes from a pool header */ void util_pool_hdr2attr(struct pool_attr *attr, struct pool_hdr *hdr) { LOG(3, "attr %p, hdr %p", attr, hdr); ASSERTne(attr, NULL); ASSERTne(hdr, NULL); memset(attr, 0, sizeof(*attr)); memcpy(attr->signature, hdr->signature, POOL_HDR_SIG_LEN); attr->major = hdr->major; attr->compat_features = hdr->compat_features; attr->incompat_features = hdr->incompat_features; attr->ro_compat_features = hdr->ro_compat_features; memcpy(attr->poolset_uuid, hdr->poolset_uuid, POOL_HDR_UUID_LEN); } /* * util_copy_attr_to_header -- copy pool attributes into pool header */ void util_pool_attr2hdr(struct pool_hdr *hdr, const struct pool_attr *attr) { LOG(3, "hdr %p, attr %p", hdr, attr); ASSERTne(hdr, NULL); ASSERTne(attr, NULL); memcpy(hdr->signature, attr->signature, POOL_HDR_SIG_LEN); hdr->major = attr->major; hdr->compat_features = attr->compat_features; hdr->incompat_features = attr->incompat_features; hdr->ro_compat_features = attr->ro_compat_features; } /* * util_unmap_all_hdrs -- unmap all pool set headers */ static void util_unmap_all_hdrs(struct pool_set *set) { LOG(3, "set %p", set); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; if (rep->remote == NULL) { for (unsigned p = 0; p < rep->nhdrs; p++) util_unmap_hdr(&rep->part[p]); } else { /* * hdr & hdrsize were set only for util_header_check(), * they will not be used any more. The memory will be * freed by util_replica_close() */ rep->part[0].hdr = NULL; rep->part[0].hdrsize = 0; } } } /* * util_replica_check -- check headers, check UUID's, check replicas linkage */ static int util_replica_check(struct pool_set *set, const struct pool_attr *attr) { LOG(3, "set %p attr %p", set, attr); for (unsigned r = 0; r < set->nreplicas; r++) { struct pool_replica *rep = set->replica[r]; for (unsigned p = 0; p < rep->nhdrs; p++) { if (util_header_check(set, r, p, attr) != 0) { LOG(2, "header check failed - part #%d", p); return -1; } set->rdonly |= rep->part[p].rdonly; } if (memcmp(HDR(REPP(set, r), 0)->uuid, HDR(REP(set, r), 0)->prev_repl_uuid, POOL_HDR_UUID_LEN) || memcmp(HDR(REPN(set, r), 0)->uuid, HDR(REP(set, r), 0)->next_repl_uuid, POOL_HDR_UUID_LEN)) { ERR("wrong replica UUID"); errno = EINVAL; return -1; } if (!set->ignore_sds && !rep->remote && rep->nhdrs) { struct shutdown_state sds; shutdown_state_init(&sds, NULL); for (unsigned p = 0; p < rep->nparts; p++) { if (shutdown_state_add_part(&sds, PART(rep, p).path, NULL)) return -1; } ASSERTne(rep->nhdrs, 0); ASSERTne(rep->nparts, 0); if (shutdown_state_check(&sds, &HDR(rep, 0)->sds, &PART(rep, 0))) { LOG(2, "ADR failure detected"); errno = EINVAL; return -1; } shutdown_state_set_flag(&HDR(rep, 0)->sds, &PART(rep, 0)); } } return 0; } /* * util_pool_open_nocheck -- open a memory pool (set or a single file) * * This function opens opens a pool set without checking the header values. */ int util_pool_open_nocheck(struct pool_set *set, int cow) { LOG(3, "set %p cow %i", set, cow); if (cow && set->replica[0]->part[0].is_dev_dax) { ERR("device dax cannot be mapped privately"); errno = ENOTSUP; return -1; } int flags = cow ? MAP_PRIVATE|MAP_NORESERVE : MAP_SHARED; int oerrno; ASSERTne(set, NULL); ASSERT(set->nreplicas > 0); if (set->remote && util_remote_load()) { ERR("the pool set requires a remote replica, " "but the '%s' library cannot be loaded", LIBRARY_REMOTE); return -1; } int ret = util_poolset_files_local(set, 0 /* minpartsize */, 0); if (ret != 0) goto err_poolset; set->rdonly = 0; for (unsigned r = 0; r < set->nreplicas; r++) { if (util_replica_open(set, r, flags) != 0) { LOG(2, "replica #%u open failed", r); goto err_replica; } } if (set->remote) { ret = util_poolset_files_remote(set, 0, NULL, 0); if (ret != 0) goto err_replica; } util_unmap_all_hdrs(set); return 0; err_replica: LOG(4, "error clean up"); oerrno = errno; for (unsigned r = 0; r < set->nreplicas; r++) util_replica_close(set, r); errno = oerrno; err_poolset: oerrno = errno; util_poolset_close(set, DO_NOT_DELETE_PARTS); errno = oerrno; return -1; } /* * util_pool_open -- open a memory pool (set or a single file) * * This routine does all the work, but takes a rdonly flag so internal * calls can map a read-only pool if required. */ int util_pool_open(struct pool_set **setp, const char *path, int cow, size_t minpartsize, const struct pool_attr *attr, unsigned *nlanes, int ignore_sds, void *addr) { LOG(3, "setp %p path %s cow %d minpartsize %zu attr %p nlanes %p " "ignore_sds %d addr %p", setp, path, cow, minpartsize, attr, nlanes, ignore_sds, addr); int flags = cow ? MAP_PRIVATE|MAP_NORESERVE : MAP_SHARED; int oerrno; /* do not check minsize */ int ret = util_poolset_create_set(setp, path, 0, 0, ignore_sds); if (ret < 0) { LOG(2, "cannot open pool set -- '%s'", path); return -1; } /* configure base mapping address for master replica */ (*setp)->replica[0]->mapaddr = addr; if (cow && (*setp)->replica[0]->part[0].is_dev_dax) { ERR("device dax cannot be mapped privately"); errno = ENOTSUP; util_poolset_free(*setp); return -1; } struct pool_set *set = *setp; ASSERT(set->nreplicas > 0); if (set->remote && util_remote_load()) { ERR("the pool set requires a remote replica, " "but the '%s' library cannot be loaded", LIBRARY_REMOTE); util_poolset_free(*setp); return -1; } ret = util_poolset_files_local(set, minpartsize, 0); if (ret != 0) goto err_poolset; for (unsigned r = 0; r < set->nreplicas; r++) { if (util_replica_open(set, r, flags) != 0) { LOG(2, "replica #%u open failed", r); goto err_replica; } } if (set->remote) { /* do not check minsize */ ret = util_poolset_files_remote(set, 0, nlanes, 0); if (ret != 0) goto err_replica; } /* check headers, check UUID's, check replicas linkage */ if (attr != NULL && util_replica_check(set, attr)) goto err_replica; /* unmap all headers */ util_unmap_all_hdrs(set); return 0; err_replica: LOG(4, "error clean up"); oerrno = errno; for (unsigned r = 0; r < set->nreplicas; r++) util_replica_close(set, r); errno = oerrno; err_poolset: oerrno = errno; util_poolset_close(set, DO_NOT_DELETE_PARTS); errno = oerrno; return -1; } /* * util_pool_open_remote -- open a remote pool set file * * This routine does all the work, but takes a rdonly flag so internal * calls can map a read-only pool if required. */ int util_pool_open_remote(struct pool_set **setp, const char *path, int cow, size_t minpartsize, struct rpmem_pool_attr *rattr) { LOG(3, "setp %p path %s cow %d minpartsize %zu rattr %p", setp, path, cow, minpartsize, rattr); int flags = cow ? MAP_PRIVATE|MAP_NORESERVE : MAP_SHARED; int oerrno; /* do not check minsize */ int ret = util_poolset_create_set(setp, path, 0, 0, 0); if (ret < 0) { LOG(2, "cannot open pool set -- '%s'", path); return -1; } if (cow && (*setp)->replica[0]->part[0].is_dev_dax) { ERR("device dax cannot be mapped privately"); errno = ENOTSUP; return -1; } struct pool_set *set = *setp; if (set->nreplicas > 1) { LOG(2, "remote pool set cannot have replicas"); goto err_poolset; } ret = util_poolset_files_local(set, minpartsize, 0); if (ret != 0) goto err_poolset; if (util_replica_open(set, 0, flags) != 0) { LOG(2, "replica open failed"); goto err_replica; } struct pool_replica *rep = set->replica[0]; set->rdonly |= rep->part[0].rdonly; /* check headers, check UUID's, check replicas linkage */ for (unsigned p = 0; p < rep->nhdrs; p++) { if (util_header_check_remote(set, p) != 0) { LOG(2, "header check failed - part #%d", p); goto err_replica; } set->rdonly |= rep->part[p].rdonly; } if (rep->nhdrs > 0) { /* header exists, copy pool attributes */ struct pool_hdr *hdr = rep->part[0].hdr; util_get_rpmem_attr(rattr, hdr); } else { /* header does not exist, zero pool attributes */ memset(rattr, 0, sizeof(*rattr)); } /* unmap all headers */ for (unsigned p = 0; p < rep->nhdrs; p++) util_unmap_hdr(&rep->part[p]); return 0; err_replica: LOG(4, "error clean up"); oerrno = errno; util_replica_close(set, 0); errno = oerrno; err_poolset: oerrno = errno; util_poolset_close(set, DO_NOT_DELETE_PARTS); errno = oerrno; return -1; } /* * util_is_poolset_file -- check if specified file is a poolset file * * Return value: * -1 - error * 0 - not a poolset * 1 - is a poolset */ int util_is_poolset_file(const char *path) { if (util_file_is_device_dax(path)) return 0; int fd = util_file_open(path, NULL, 0, O_RDONLY); if (fd < 0) return -1; int ret = 0; ssize_t sret; char signature[POOLSET_HDR_SIG_LEN]; size_t rd = 0; do { sret = util_read(fd, &signature[rd], sizeof(signature) - rd); if (sret > 0) rd += (size_t)sret; } while (sret > 0); if (sret < 0) { ERR("!read"); ret = -1; goto out; } else if (rd != sizeof(signature)) { ret = 0; goto out; } if (memcmp(signature, POOLSET_HDR_SIG, POOLSET_HDR_SIG_LEN) == 0) ret = 1; out: os_close(fd); return ret; } /* * util_poolset_foreach_part -- walk through all poolset file parts * * Stops processing if callback returns non-zero value. * The value returned by callback is returned to the caller. * * Return value: * 0 - all part files have been processed * -1 - parsing poolset file error */ int util_poolset_foreach_part(const char *path, int (*cb)(struct part_file *pf, void *arg), void *arg) { int fd = os_open(path, O_RDONLY); if (fd < 0) return -1; struct pool_set *set; int ret = util_poolset_parse(&set, path, fd); if (ret) { ret = -1; goto err_close; } for (unsigned r = 0; r < set->nreplicas; r++) { struct part_file part; if (set->replica[r]->remote) { part.is_remote = 1; part.node_addr = set->replica[r]->remote->node_addr; part.pool_desc = set->replica[r]->remote->pool_desc; ret = cb(&part, arg); if (ret) goto out; } else { part.is_remote = 0; for (unsigned p = 0; p < set->replica[r]->nparts; p++) { part.path = set->replica[r]->part[p].path; ret = cb(&part, arg); if (ret) goto out; } } } out: /* * Make sure callback does not return -1, * because this value is reserved for parsing * error. */ ASSERTne(ret, -1); util_poolset_free(set); err_close: os_close(fd); return ret; } /* * util_poolset_size -- get size of poolset, returns 0 on error */ size_t util_poolset_size(const char *path) { int fd = os_open(path, O_RDONLY); if (fd < 0) return 0; size_t size = 0; struct pool_set *set; if (util_poolset_parse(&set, path, fd)) goto err_close; size = set->poolsize; util_poolset_free(set); err_close: os_close(fd); return size; } /* * util_replica_fdclose -- close all parts of given replica */ void util_replica_fdclose(struct pool_replica *rep) { for (unsigned p = 0; p < rep->nparts; p++) { struct pool_set_part *part = &rep->part[p]; util_part_fdclose(part); } } /* * util_replica_deep_common -- performs common calculations * on all parts from replica to define intersection ranges * for final flushing operations that take place in * os_part_deep_common function. */ int util_replica_deep_common(const void *addr, size_t len, struct pool_set *set, unsigned replica_id, int flush) { LOG(3, "addr %p len %zu set %p replica_id %u flush %d", addr, len, set, replica_id, flush); struct pool_replica *rep = set->replica[replica_id]; uintptr_t rep_start = (uintptr_t)rep->part[0].addr; uintptr_t rep_end = rep_start + rep->repsize; uintptr_t start = (uintptr_t)addr; uintptr_t end = start + len; ASSERT(start >= rep_start); ASSERT(end <= rep_end); for (unsigned p = 0; p < rep->nparts; p++) { struct pool_set_part *part = &rep->part[p]; uintptr_t part_start = (uintptr_t)part->addr; uintptr_t part_end = part_start + part->size; /* init intersection start and end addresses */ uintptr_t range_start = start; uintptr_t range_end = end; if (part_start > end || part_end < start) continue; /* recalculate intersection addresses */ if (part_start > start) range_start = part_start; if (part_end < end) range_end = part_end; size_t range_len = range_end - range_start; LOG(15, "perform deep flushing for replica %u " "part %p, addr %p, len %lu", replica_id, part, (void *)range_start, range_len); if (os_part_deep_common(part, (void *)range_start, range_len, flush)) { LOG(1, "os_part_deep_common(%p, %p, %lu)", part, (void *)range_start, range_len); return -1; } } return 0; } /* * util_replica_deep_persist -- wrapper for util_replica_deep_common * Calling the target precedes initialization of function that * partly defines way of deep replica flushing. */ int util_replica_deep_persist(const void *addr, size_t len, struct pool_set *set, unsigned replica_id) { LOG(3, "addr %p len %zu set %p replica_id %u", addr, len, set, replica_id); int flush = 1; return util_replica_deep_common(addr, len, set, replica_id, flush); } /* * util_replica_deep_drain -- wrapper for util_replica_deep_common * Calling the target precedes initialization of function that * partly defines way of deep replica flushing. */ int util_replica_deep_drain(const void *addr, size_t len, struct pool_set *set, unsigned replica_id) { LOG(3, "addr %p len %zu set %p replica_id %u", addr, len, set, replica_id); int flush = 0; return util_replica_deep_common(addr, len, set, replica_id, flush); } pmdk-1.4.1/src/common/set.h000066400000000000000000000275761331545616200155220ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * set.h -- internal definitions for set module */ #ifndef PMDK_SET_H #define PMDK_SET_H 1 #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include "vec.h" #include "pool_hdr.h" #include "librpmem.h" /* * pool sets & replicas */ #define POOLSET_HDR_SIG "PMEMPOOLSET" #define POOLSET_HDR_SIG_LEN 11 /* does NOT include '\0' */ #define POOLSET_REPLICA_SIG "REPLICA" #define POOLSET_REPLICA_SIG_LEN 7 /* does NOT include '\0' */ #define POOLSET_OPTION_SIG "OPTION" #define POOLSET_OPTION_SIG_LEN 6 /* does NOT include '\0' */ /* pool set option flags */ enum pool_set_option_flag { OPTION_UNKNOWN = 0x0, OPTION_SINGLEHDR = 0x1, /* pool headers only in the first part */ OPTION_NOHDRS = 0x2, /* no pool headers, remote replicas only */ }; struct pool_set_option { const char *name; enum pool_set_option_flag flag; }; #define POOL_LOCAL 0 #define POOL_REMOTE 1 #define REPLICAS_DISABLED 0 #define REPLICAS_ENABLED 1 enum del_parts_mode { DO_NOT_DELETE_PARTS, /* do not delete part files */ DELETE_CREATED_PARTS, /* delete only newly created parts files */ DELETE_ALL_PARTS /* force delete all parts files */ }; struct pool_set_part { /* populated by a pool set file parser */ const char *path; size_t filesize; /* aligned to page size */ int fd; int flags; /* stores flags used when opening the file */ /* valid only if fd >= 0 */ int is_dev_dax; /* indicates if the part is on device dax */ size_t alignment; /* internal alignment (Device DAX only) */ int created; /* indicates newly created (zeroed) file */ /* util_poolset_open/create */ void *remote_hdr; /* allocated header for remote replica */ void *hdr; /* base address of header */ size_t hdrsize; /* size of the header mapping */ int hdr_map_sync; /* header mapped with MAP_SYNC */ void *addr; /* base address of the mapping */ size_t size; /* size of the mapping - page aligned */ int map_sync; /* part has been mapped with MAP_SYNC flag */ int rdonly; /* is set based on compat features, affects */ /* the whole poolset */ uuid_t uuid; }; struct pool_set_directory { const char *path; size_t resvsize; /* size of the address space reservation */ }; struct remote_replica { void *rpp; /* RPMEMpool opaque handle */ char *node_addr; /* address of a remote node */ /* poolset descriptor is a pool set file name on a remote node */ char *pool_desc; /* descriptor of a poolset */ }; struct pool_replica { unsigned nparts; unsigned nallocated; unsigned nhdrs; /* should be 0, 1 or nparts */ size_t repsize; /* total size of all the parts (mappings) */ size_t resvsize; /* min size of the address space reservation */ int is_pmem; /* true if all the parts are in PMEM */ void *mapaddr; /* base address (libpmemcto only) */ struct remote_replica *remote; /* not NULL if the replica */ /* is a remote one */ VEC(, struct pool_set_directory) directory; struct pool_set_part part[]; }; struct pool_set { unsigned nreplicas; uuid_t uuid; int rdonly; int zeroed; /* true if all the parts are new files */ size_t poolsize; /* the smallest replica size */ int remote; /* true if contains a remote replica */ unsigned options; /* enabled pool set options */ int directory_based; size_t resvsize; unsigned next_id; unsigned next_directory_id; int ignore_sds; /* don't use shutdown state */ struct pool_replica *replica[]; }; struct part_file { int is_remote; const char *path; /* not-NULL only for a local part file */ const char *node_addr; /* address of a remote node */ /* poolset descriptor is a pool set file name on a remote node */ const char *pool_desc; /* descriptor of a poolset */ }; struct pool_attr { char signature[POOL_HDR_SIG_LEN]; /* pool signature */ uint32_t major; /* format major version number */ uint32_t compat_features; /* mask: compatible "may" features */ uint32_t incompat_features; /* mask: "must support" features */ uint32_t ro_compat_features; /* mask: force RO if unsupported */ unsigned char poolset_uuid[POOL_HDR_UUID_LEN]; /* pool uuid */ unsigned char first_part_uuid[POOL_HDR_UUID_LEN]; /* first part uuid */ unsigned char prev_repl_uuid[POOL_HDR_UUID_LEN]; /* prev replica uuid */ unsigned char next_repl_uuid[POOL_HDR_UUID_LEN]; /* next replica uuid */ unsigned char arch_flags[POOL_HDR_ARCH_LEN]; /* arch flags */ }; /* get index of the (r)th replica */ #define REPidx(set, r) (((set)->nreplicas + (r)) % (set)->nreplicas) /* get index of the (r + 1)th replica */ #define REPNidx(set, r) (((set)->nreplicas + (r) + 1) % (set)->nreplicas) /* get index of the (r - 1)th replica */ #define REPPidx(set, r) (((set)->nreplicas + (r) - 1) % (set)->nreplicas) /* get index of the (r)th part */ #define PARTidx(rep, p) (((rep)->nparts + (p)) % (rep)->nparts) /* get index of the (r + 1)th part */ #define PARTNidx(rep, p) (((rep)->nparts + (p) + 1) % (rep)->nparts) /* get index of the (r - 1)th part */ #define PARTPidx(rep, p) (((rep)->nparts + (p) - 1) % (rep)->nparts) /* get index of the (r)th part */ #define HDRidx(rep, p) (((rep)->nhdrs + (p)) % (rep)->nhdrs) /* get index of the (r + 1)th part */ #define HDRNidx(rep, p) (((rep)->nhdrs + (p) + 1) % (rep)->nhdrs) /* get index of the (r - 1)th part */ #define HDRPidx(rep, p) (((rep)->nhdrs + (p) - 1) % (rep)->nhdrs) /* get (r)th replica */ #define REP(set, r)\ ((set)->replica[REPidx(set, r)]) /* get (r + 1)th replica */ #define REPN(set, r)\ ((set)->replica[REPNidx(set, r)]) /* get (r - 1)th replica */ #define REPP(set, r)\ ((set)->replica[REPPidx(set, r)]) #define PART(rep, p)\ ((rep)->part[PARTidx(rep, p)]) #define PARTN(rep, p)\ ((rep)->part[PARTNidx(rep, p)]) #define PARTP(rep, p)\ ((rep)->part[PARTPidx(rep, p)]) #define HDR(rep, p)\ ((struct pool_hdr *)(((rep)->part[HDRidx(rep, p)]).hdr)) #define HDRN(rep, p)\ ((struct pool_hdr *)(((rep)->part[HDRNidx(rep, p)]).hdr)) #define HDRP(rep, p)\ ((struct pool_hdr *)(((rep)->part[HDRPidx(rep, p)]).hdr)) extern int Prefault_at_open; extern int Prefault_at_create; int util_poolset_parse(struct pool_set **setp, const char *path, int fd); int util_poolset_read(struct pool_set **setp, const char *path); int util_poolset_create_set(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, int ignore_sds); int util_poolset_open(struct pool_set *set); void util_poolset_close(struct pool_set *set, enum del_parts_mode del); void util_poolset_free(struct pool_set *set); int util_poolset_chmod(struct pool_set *set, mode_t mode); void util_poolset_fdclose(struct pool_set *set); void util_poolset_fdclose_always(struct pool_set *set); int util_is_poolset_file(const char *path); int util_poolset_foreach_part(const char *path, int (*cb)(struct part_file *pf, void *arg), void *arg); size_t util_poolset_size(const char *path); int util_replica_deep_common(const void *addr, size_t len, struct pool_set *set, unsigned replica_id, int flush); int util_replica_deep_persist(const void *addr, size_t len, struct pool_set *set, unsigned replica_id); int util_replica_deep_drain(const void *addr, size_t len, struct pool_set *set, unsigned replica_id); int util_pool_create(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, size_t minpartsize, const struct pool_attr *attr, unsigned *nlanes, int can_have_rep); int util_pool_create_uuids(struct pool_set **setp, const char *path, size_t poolsize, size_t minsize, size_t minpartsize, const struct pool_attr *attr, unsigned *nlanes, int can_have_rep, int remote); int util_part_open(struct pool_set_part *part, size_t minsize, int create); void util_part_fdclose(struct pool_set_part *part); int util_replica_open(struct pool_set *set, unsigned repidx, int flags); int util_replica_set_attr(struct pool_replica *rep, const struct rpmem_pool_attr *rattr); void util_pool_hdr2attr(struct pool_attr *attr, struct pool_hdr *hdr); void util_pool_attr2hdr(struct pool_hdr *hdr, const struct pool_attr *attr); int util_replica_close(struct pool_set *set, unsigned repidx); int util_map_part(struct pool_set_part *part, void *addr, size_t size, size_t offset, int flags, int rdonly); int util_unmap_part(struct pool_set_part *part); int util_unmap_parts(struct pool_replica *rep, unsigned start_index, unsigned end_index); int util_header_create(struct pool_set *set, unsigned repidx, unsigned partidx, const struct pool_attr *attr, int overwrite); int util_map_hdr(struct pool_set_part *part, int flags, int rdonly); int util_unmap_hdr(struct pool_set_part *part); int util_pool_open_nocheck(struct pool_set *set, int cow); int util_pool_open(struct pool_set **setp, const char *path, int cow, size_t minpartsize, const struct pool_attr *attr, unsigned *nlanes, int ignore_sds, void *addr); int util_pool_open_remote(struct pool_set **setp, const char *path, int cow, size_t minpartsize, struct rpmem_pool_attr *rattr); void *util_pool_extend(struct pool_set *set, size_t *size, size_t minpartsize); void util_remote_init(void); void util_remote_fini(void); int util_update_remote_header(struct pool_set *set, unsigned repn); void util_remote_init_lock(void); void util_remote_destroy_lock(void); int util_pool_close_remote(RPMEMpool *rpp); void util_remote_unload(void); void util_replica_fdclose(struct pool_replica *rep); int util_poolset_remote_open(struct pool_replica *rep, unsigned repidx, size_t minsize, int create, void *pool_addr, size_t pool_size, unsigned *nlanes); int util_remote_load(void); int util_replica_open_remote(struct pool_set *set, unsigned repidx, int flags); int util_poolset_remote_replica_open(struct pool_set *set, unsigned repidx, size_t minsize, int create, unsigned *nlanes); int util_replica_close_local(struct pool_replica *rep, unsigned repn, enum del_parts_mode del); int util_replica_close_remote(struct pool_replica *rep, unsigned repn, enum del_parts_mode del); extern int (*Rpmem_persist)(RPMEMpool *rpp, size_t offset, size_t length, unsigned lane); extern int (*Rpmem_deep_persist)(RPMEMpool *rpp, size_t offset, size_t length, unsigned lane); extern int (*Rpmem_read)(RPMEMpool *rpp, void *buff, size_t offset, size_t length, unsigned lane); extern int (*Rpmem_close)(RPMEMpool *rpp); extern int (*Rpmem_remove)(const char *target, const char *pool_set_name, int flags); extern int (*Rpmem_set_attr)(RPMEMpool *rpp, const struct rpmem_pool_attr *rattr); #ifdef __cplusplus } #endif #endif pmdk-1.4.1/src/common/shutdown_state.c000066400000000000000000000140071331545616200177560ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * shutdown_state.c -- unsafe shudown detection */ #include #include #include #include "shutdown_state.h" #include "os_dimm.h" #include "out.h" #include "util.h" #include "os_deep.h" #define FLUSH_SDS(sds, part) \ if (part != NULL) os_part_deep_common(part, sds, sizeof(*sds), 1) /* * shutdown_state_checksum -- (internal) counts SDS checksum and flush it */ static void shutdown_state_checksum(struct shutdown_state *sds, struct pool_set_part *part) { LOG(3, "sds %p", sds); util_checksum(sds, sizeof(*sds), &sds->checksum, 1, 0); FLUSH_SDS(sds, part); } /* * shutdown_state_init -- initializes shutdown_state struct */ int shutdown_state_init(struct shutdown_state *sds, struct pool_set_part *part) { /* check if we didn't change size of shutdown_state accidentally */ COMPILE_ERROR_ON(sizeof(struct shutdown_state) != 64); LOG(3, "sds %p", sds); memset(sds, 0, sizeof(*sds)); shutdown_state_checksum(sds, part); return 0; } /* * shutdown_state_add_part -- adds file uuid and usc to shutdown_state struct */ int shutdown_state_add_part(struct shutdown_state *sds, const char *path, struct pool_set_part *part) { LOG(3, "sds %p, path %s", sds, path); size_t len = 0; char *uid; uint64_t usc; if (os_dimm_usc(path, &usc)) { ERR("cannot read unsafe shutdown count of %s", path); return 1; } if (os_dimm_uid(path, NULL, &len)) { ERR("cannot read uuid of %s", path); return 1; } len += 4 - len % 4; uid = Zalloc(len); if (uid == NULL) { ERR("!Zalloc"); return 1; } if (os_dimm_uid(path, uid, &len)) { ERR("cannot read uuid of %s", path); Free(uid); return 1; } sds->usc = htole64(le64toh(sds->usc) + usc); uint64_t tmp; util_checksum(uid, len, &tmp, 1, 0); sds->uuid = htole64(le64toh(sds->uuid) + tmp); FLUSH_SDS(sds, part); Free(uid); shutdown_state_checksum(sds, part); return 0; } /* * shutdown_state_set_flag -- sets dirty pool flag */ void shutdown_state_set_flag(struct shutdown_state *sds, struct pool_set_part *part) { LOG(3, "sds %p", sds); /* set dirty flag only if uid is non-zero */ if (sds->uuid != 0) sds->dirty = 1; FLUSH_SDS(sds, part); shutdown_state_checksum(sds, part); } /* * pmem_shutdown_clear_flag -- clears dirty pool flag */ void shutdown_state_clear_flag(struct shutdown_state *sds, struct pool_set_part *part) { LOG(3, "sds %p", sds); sds->dirty = 0; FLUSH_SDS(sds, part); shutdown_state_checksum(sds, part); } /* * shutdown_state_reinit -- (internal) reinitializes shutdown_state struct */ static void shutdown_state_reinit(struct shutdown_state *curr_sds, struct shutdown_state *pool_sds, struct pool_set_part *part) { LOG(3, "curr_sds %p, pool_sds %p", curr_sds, pool_sds); shutdown_state_init((struct shutdown_state *)pool_sds, part); pool_sds->uuid = htole64(curr_sds->uuid); pool_sds->usc = htole64(curr_sds->usc); pool_sds->dirty = 0; FLUSH_SDS(pool_sds, part); shutdown_state_checksum(pool_sds, part); } /* * shutdown_state_check -- compares and fixes shutdown state */ int shutdown_state_check(struct shutdown_state *curr_sds, struct shutdown_state *pool_sds, struct pool_set_part *part) { LOG(3, "curr_sds %p, pool_sds %p", curr_sds, pool_sds); if (util_is_zeroed(pool_sds, sizeof(*pool_sds)) && !util_is_zeroed(curr_sds, sizeof(*curr_sds))) { shutdown_state_reinit(curr_sds, pool_sds, part); return 0; } bool is_uuid_usc_correct = le64toh(pool_sds->usc) == le64toh(curr_sds->usc) && le64toh(pool_sds->uuid) == le64toh(curr_sds->uuid); bool is_checksum_correct = util_checksum(pool_sds, sizeof(*pool_sds), &pool_sds->checksum, 0, 0); int dirty = pool_sds->dirty; if (!is_checksum_correct) { /* the program was killed during opening or closing the pool */ LOG(2, "incorrect checksum - SDS will be reinitialized"); shutdown_state_reinit(curr_sds, pool_sds, part); return 0; } if (is_uuid_usc_correct) { if (dirty == 0) return 0; /* * the program was killed when the pool was opened * but there wasn't an ADR failure */ LOG(2, "the pool was not closed - SDS will be reinitialized"); shutdown_state_reinit(curr_sds, pool_sds, part); return 0; } if (dirty == 0) { /* an ADR failure but the pool was closed */ LOG(2, "an ADR failure was detected but the pool was closed - SDS will be reinitialized"); shutdown_state_reinit(curr_sds, pool_sds, part); return 0; } /* an ADR failure - the pool might be corrupted */ ERR("an ADR failure was detected, the pool might be corrupted"); return 1; } pmdk-1.4.1/src/common/shutdown_state.h000066400000000000000000000045571331545616200177740ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * shutdown_state.h -- unsafe shudown detection */ #ifndef PMDK_SHUTDOWN_STATE_H #define PMDK_SHUTDOWN_STATE_H 1 #include struct pool_set_part; struct shutdown_state { uint64_t usc; uint64_t uuid; /* UID checksum */ uint8_t dirty; uint8_t reserved[39]; uint64_t checksum; }; int shutdown_state_init(struct shutdown_state *sds, struct pool_set_part *part); int shutdown_state_add_part(struct shutdown_state *sds, const char *path, struct pool_set_part *part); void shutdown_state_set_flag(struct shutdown_state *sds, struct pool_set_part *part); void shutdown_state_clear_flag(struct shutdown_state *sds, struct pool_set_part *part); int shutdown_state_check(struct shutdown_state *curr_sds, struct shutdown_state *pool_sds, struct pool_set_part *part); #endif /* shutdown_state.h */ pmdk-1.4.1/src/common/sys_util.h000066400000000000000000000157471331545616200165770ustar00rootroot00000000000000/* * Copyright 2016-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * sys_util.h -- internal utility wrappers around system functions */ #ifndef PMDK_SYS_UTIL_H #define PMDK_SYS_UTIL_H 1 #include #include "os_thread.h" /* * util_mutex_init -- os_mutex_init variant that never fails from * caller perspective. If os_mutex_init failed, this function aborts * the program. */ static inline void util_mutex_init(os_mutex_t *m) { int tmp = os_mutex_init(m); if (tmp) { errno = tmp; FATAL("!os_mutex_init"); } } /* * util_mutex_destroy -- os_mutex_destroy variant that never fails from * caller perspective. If os_mutex_destroy failed, this function aborts * the program. */ static inline void util_mutex_destroy(os_mutex_t *m) { int tmp = os_mutex_destroy(m); if (tmp) { errno = tmp; FATAL("!os_mutex_destroy"); } } /* * util_mutex_lock -- os_mutex_lock variant that never fails from * caller perspective. If os_mutex_lock failed, this function aborts * the program. */ static inline void util_mutex_lock(os_mutex_t *m) { int tmp = os_mutex_lock(m); if (tmp) { errno = tmp; FATAL("!os_mutex_lock"); } } /* * util_mutex_unlock -- os_mutex_unlock variant that never fails from * caller perspective. If os_mutex_unlock failed, this function aborts * the program. */ static inline void util_mutex_unlock(os_mutex_t *m) { int tmp = os_mutex_unlock(m); if (tmp) { errno = tmp; FATAL("!os_mutex_unlock"); } } /* * util_rwlock_init -- os_rwlock_init variant that never fails from * caller perspective. If os_rwlock_init failed, this function aborts * the program. */ static inline void util_rwlock_init(os_rwlock_t *m) { int tmp = os_rwlock_init(m); if (tmp) { errno = tmp; FATAL("!os_rwlock_init"); } } /* * util_rwlock_rdlock -- os_rwlock_rdlock variant that never fails from * caller perspective. If os_rwlock_rdlock failed, this function aborts * the program. */ static inline void util_rwlock_rdlock(os_rwlock_t *m) { int tmp = os_rwlock_rdlock(m); if (tmp) { errno = tmp; FATAL("!os_rwlock_rdlock"); } } /* * util_rwlock_wrlock -- os_rwlock_wrlock variant that never fails from * caller perspective. If os_rwlock_wrlock failed, this function aborts * the program. */ static inline void util_rwlock_wrlock(os_rwlock_t *m) { int tmp = os_rwlock_wrlock(m); if (tmp) { errno = tmp; FATAL("!os_rwlock_wrlock"); } } /* * util_rwlock_unlock -- os_rwlock_unlock variant that never fails from * caller perspective. If os_rwlock_unlock failed, this function aborts * the program. */ static inline void util_rwlock_unlock(os_rwlock_t *m) { int tmp = os_rwlock_unlock(m); if (tmp) { errno = tmp; FATAL("!os_rwlock_unlock"); } } /* * util_rwlock_destroy -- os_rwlock_destroy variant that never fails from * caller perspective. If os_rwlock_destroy failed, this function aborts * the program. */ static inline void util_rwlock_destroy(os_rwlock_t *m) { int tmp = os_rwlock_destroy(m); if (tmp) { errno = tmp; FATAL("!os_rwlock_destroy"); } } /* * util_spin_init -- os_spin_init variant that logs on fail and sets errno. */ static inline int util_spin_init(os_spinlock_t *lock, int pshared) { int tmp = os_spin_init(lock, pshared); if (tmp) { errno = tmp; ERR("!os_spin_init"); } return tmp; } /* * util_spin_destroy -- os_spin_destroy variant that never fails from * caller perspective. If os_spin_destroy failed, this function aborts * the program. */ static inline void util_spin_destroy(os_spinlock_t *lock) { int tmp = os_spin_destroy(lock); if (tmp) { errno = tmp; FATAL("!os_spin_destroy"); } } /* * util_spin_lock -- os_spin_lock variant that never fails from caller * perspective. If os_spin_lock failed, this function aborts the program. */ static inline void util_spin_lock(os_spinlock_t *lock) { int tmp = os_spin_lock(lock); if (tmp) { errno = tmp; FATAL("!os_spin_lock"); } } /* * util_spin_unlock -- os_spin_unlock variant that never fails * from caller perspective. If os_spin_unlock failed, * this function aborts the program. */ static inline void util_spin_unlock(os_spinlock_t *lock) { int tmp = os_spin_unlock(lock); if (tmp) { errno = tmp; FATAL("!os_spin_unlock"); } } /* * util_semaphore_init -- os_semaphore_init variant that never fails * from caller perspective. If os_semaphore_init failed, * this function aborts the program. */ static inline void util_semaphore_init(os_semaphore_t *sem, unsigned value) { if (os_semaphore_init(sem, value)) FATAL("!os_semaphore_init"); } /* * util_semaphore_destroy -- deletes a semaphore instance */ static inline void util_semaphore_destroy(os_semaphore_t *sem) { if (os_semaphore_destroy(sem) != 0) FATAL("!os_semaphore_destroy"); } /* * util_semaphore_wait -- decreases the value of the semaphore */ static inline void util_semaphore_wait(os_semaphore_t *sem) { errno = 0; int ret; do { ret = os_semaphore_wait(sem); } while (errno == EINTR); /* signal interrupt */ if (ret != 0) FATAL("!os_semaphore_wait"); } /* * util_semaphore_trywait -- tries to decrease the value of the semaphore */ static inline int util_semaphore_trywait(os_semaphore_t *sem) { errno = 0; int ret; do { ret = os_semaphore_trywait(sem); } while (errno == EINTR); /* signal interrupt */ if (ret != 0 && errno != EAGAIN) FATAL("!os_semaphore_trywait"); return ret; } /* * util_semaphore_post -- increases the value of the semaphore */ static inline void util_semaphore_post(os_semaphore_t *sem) { if (os_semaphore_post(sem) != 0) FATAL("!os_semaphore_post"); } #endif pmdk-1.4.1/src/common/util.c000066400000000000000000000155041331545616200156630ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * util.c -- very basic utilities */ #include #include #include #include #include #include #include #include "util.h" #include "valgrind_internal.h" /* library-wide page size */ unsigned long long Pagesize; /* allocation/mmap granularity */ unsigned long long Mmap_align; /* * our versions of malloc & friends start off pointing to the libc versions */ Malloc_func Malloc = malloc; Free_func Free = free; Realloc_func Realloc = realloc; Strdup_func Strdup = strdup; /* * Zalloc -- allocate zeroed memory */ void * Zalloc(size_t sz) { void *ret = Malloc(sz); if (!ret) return NULL; return memset(ret, 0, sz); } #if ANY_VG_TOOL_ENABLED /* initialized to true if the process is running inside Valgrind */ unsigned _On_valgrind; #endif /* * util_is_zeroed -- check if given memory range is all zero */ int util_is_zeroed(const void *addr, size_t len) { /* XXX optimize */ const char *a = addr; while (len-- > 0) if (*a++) return 0; return 1; } /* * util_checksum -- compute Fletcher64 checksum * * csump points to where the checksum lives, so that location * is treated as zeros while calculating the checksum. The * checksummed data is assumed to be in little endian order. * If insert is true, the calculated checksum is inserted into * the range at *csump. Otherwise the calculated checksum is * checked against *csump and the result returned (true means * the range checksummed correctly). */ int util_checksum(void *addr, size_t len, uint64_t *csump, int insert, size_t skip_off) { if (len % 4 != 0) abort(); uint32_t *p32 = addr; uint32_t *p32end = (uint32_t *)((char *)addr + len); uint32_t *skip; uint32_t lo32 = 0; uint32_t hi32 = 0; uint64_t csum; if (skip_off) skip = (uint32_t *)((char *)addr + skip_off); else skip = (uint32_t *)((char *)addr + len); while (p32 < p32end) if (p32 == (uint32_t *)csump || p32 >= skip) { /* lo32 += 0; treat first 32-bits as zero */ p32++; hi32 += lo32; /* lo32 += 0; treat second 32-bits as zero */ p32++; hi32 += lo32; } else { lo32 += le32toh(*p32); ++p32; hi32 += lo32; } csum = (uint64_t)hi32 << 32 | lo32; if (insert) { *csump = htole64(csum); return 1; } return *csump == htole64(csum); } /* * util_set_alloc_funcs -- allow one to override malloc, etc. */ void util_set_alloc_funcs(void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s)) { Malloc = (malloc_func == NULL) ? malloc : malloc_func; Free = (free_func == NULL) ? free : free_func; Realloc = (realloc_func == NULL) ? realloc : realloc_func; Strdup = (strdup_func == NULL) ? strdup : strdup_func; } /* * util_fgets -- fgets wrapper with conversion CRLF to LF */ char * util_fgets(char *buffer, int max, FILE *stream) { char *str = fgets(buffer, max, stream); if (str == NULL) goto end; int len = (int)strlen(str); if (len < 2) goto end; if (str[len - 2] == '\r' && str[len - 1] == '\n') { str[len - 2] = '\n'; str[len - 1] = '\0'; } end: return str; } struct suff { const char *suff; uint64_t mag; }; /* * util_parse_size -- parse size from string */ int util_parse_size(const char *str, size_t *sizep) { const struct suff suffixes[] = { { "B", 1ULL }, { "K", 1ULL << 10 }, /* JEDEC */ { "M", 1ULL << 20 }, { "G", 1ULL << 30 }, { "T", 1ULL << 40 }, { "P", 1ULL << 50 }, { "KiB", 1ULL << 10 }, /* IEC */ { "MiB", 1ULL << 20 }, { "GiB", 1ULL << 30 }, { "TiB", 1ULL << 40 }, { "PiB", 1ULL << 50 }, { "kB", 1000ULL }, /* SI */ { "MB", 1000ULL * 1000 }, { "GB", 1000ULL * 1000 * 1000 }, { "TB", 1000ULL * 1000 * 1000 * 1000 }, { "PB", 1000ULL * 1000 * 1000 * 1000 * 1000 } }; int res = -1; unsigned i; size_t size = 0; char unit[9] = {0}; int ret = sscanf(str, "%zu%8s", &size, unit); if (ret == 1) { res = 0; } else if (ret == 2) { for (i = 0; i < ARRAY_SIZE(suffixes); ++i) { if (strcmp(suffixes[i].suff, unit) == 0) { size = size * suffixes[i].mag; res = 0; break; } } } else { return -1; } if (sizep && res == 0) *sizep = size; return res; } /* * util_init -- initialize the utils * * This is called from the library initialization code. */ void util_init(void) { /* XXX - replace sysconf() with util_get_sys_xxx() */ if (Pagesize == 0) Pagesize = (unsigned long) sysconf(_SC_PAGESIZE); #ifndef _WIN32 Mmap_align = Pagesize; #else if (Mmap_align == 0) { SYSTEM_INFO si; GetSystemInfo(&si); Mmap_align = si.dwAllocationGranularity; } #endif #if ANY_VG_TOOL_ENABLED _On_valgrind = RUNNING_ON_VALGRIND; #endif } /* * util_concat_str -- concatenate two strings */ char * util_concat_str(const char *s1, const char *s2) { char *result = malloc(strlen(s1) + strlen(s2) + 1); if (!result) return NULL; strcpy(result, s1); strcat(result, s2); return result; } /* * util_localtime -- a wrapper for localtime function * * localtime can set nonzero errno even if it succeeds (e.g. when there is no * /etc/localtime file under Linux) and we do not want the errno to be polluted * in such cases. */ struct tm * util_localtime(const time_t *timep) { int oerrno = errno; struct tm *tm = localtime(timep); if (tm != NULL) errno = oerrno; return tm; } pmdk-1.4.1/src/common/util.h000066400000000000000000000366221331545616200156740ustar00rootroot00000000000000/* * Copyright 2014-2018, Intel Corporation * Copyright (c) 2016, Microsoft Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * util.h -- internal definitions for util module */ #ifndef PMDK_UTIL_H #define PMDK_UTIL_H 1 #ifdef __cplusplus extern "C" { #endif #include #include #include #include #ifdef _MSC_VER #include /* popcnt, bitscan */ #endif #include extern unsigned long long Pagesize; extern unsigned long long Mmap_align; #define PAGE_ALIGNED_DOWN_SIZE(size) ((size) & ~(Pagesize - 1)) #define PAGE_ALIGNED_UP_SIZE(size)\ PAGE_ALIGNED_DOWN_SIZE((size) + (Pagesize - 1)) #define IS_PAGE_ALIGNED(size) (((size) & (Pagesize - 1)) == 0) #define PAGE_ALIGN_UP(addr) ((void *)PAGE_ALIGNED_UP_SIZE((uintptr_t)(addr))) #define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1)) #define ALIGN_DOWN(size, align) ((size) & ~((align) - 1)) #define ADDR_SUM(vp, lp) ((void *)((char *)(vp) + lp)) #define util_alignof(t) offsetof(struct {char _util_c; t _util_m; }, _util_m) #define FORMAT_PRINTF(a, b) __attribute__((__format__(__printf__, (a), (b)))) /* * overridable names for malloc & friends used by this library */ typedef void *(*Malloc_func)(size_t size); typedef void (*Free_func)(void *ptr); typedef void *(*Realloc_func)(void *ptr, size_t size); typedef char *(*Strdup_func)(const char *s); extern Malloc_func Malloc; extern Free_func Free; extern Realloc_func Realloc; extern Strdup_func Strdup; extern void *Zalloc(size_t sz); void util_init(void); int util_is_zeroed(const void *addr, size_t len); int util_checksum(void *addr, size_t len, uint64_t *csump, int insert, size_t skip_off); int util_parse_size(const char *str, size_t *sizep); char *util_fgets(char *buffer, int max, FILE *stream); char *util_getexecname(char *path, size_t pathlen); char *util_part_realpath(const char *path); int util_compare_file_inodes(const char *path1, const char *path2); void *util_aligned_malloc(size_t alignment, size_t size); void util_aligned_free(void *ptr); struct tm *util_localtime(const time_t *timep); #ifdef _WIN32 char *util_toUTF8(const wchar_t *wstr); wchar_t *util_toUTF16(const char *wstr); void util_free_UTF8(char *str); void util_free_UTF16(wchar_t *str); int util_toUTF16_buff(const char *in, wchar_t *out, size_t out_size); int util_toUTF8_buff(const wchar_t *in, char *out, size_t out_size); #endif #define UTIL_MAX_ERR_MSG 128 void util_strerror(int errnum, char *buff, size_t bufflen); void util_set_alloc_funcs( void *(*malloc_func)(size_t size), void (*free_func)(void *ptr), void *(*realloc_func)(void *ptr, size_t size), char *(*strdup_func)(const char *s)); /* * Macro calculates number of elements in given table */ #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #ifdef _MSC_VER #define force_inline inline __forceinline #else #define force_inline __attribute__((always_inline)) inline #endif /* * util_setbit -- setbit macro substitution which properly deals with types */ static inline void util_setbit(uint8_t *b, uint32_t i) { b[i / 8] = (uint8_t)(b[i / 8] | (uint8_t)(1 << (i % 8))); } /* * util_clrbit -- clrbit macro substitution which properly deals with types */ static inline void util_clrbit(uint8_t *b, uint32_t i) { b[i / 8] = (uint8_t)(b[i / 8] & (uint8_t)(~(1 << (i % 8)))); } #define util_isset(a, i) isset(a, i) #define util_isclr(a, i) isclr(a, i) #define util_flag_isset(a, f) ((a) & (f)) #define util_flag_isclr(a, f) (((a) & (f)) == 0) /* * util_is_pow2 -- returns !0 when there's only 1 bit set in v, 0 otherwise */ static force_inline int util_is_pow2(uint64_t v) { return v && !(v & (v - 1)); } /* * util_bool_compare_and_swap -- perform an atomic compare and swap * util_fetch_and_* -- perform an operation atomically, return old value * util_synchronize -- issue a full memory barrier * util_popcount -- count number of set bits * util_lssb_index -- return index of least significant set bit, * undefined on zero * util_mssb_index -- return index of most significant set bit * undefined on zero * * XXX assertions needed on (value != 0) in both versions of bitscans * */ #ifndef _MSC_VER /* * ISO C11 -- 7.17.1.4 * memory_order - an enumerated type whose enumerators identify memory ordering * constraints. */ typedef enum { memory_order_relaxed = __ATOMIC_RELAXED, memory_order_consume = __ATOMIC_CONSUME, memory_order_acquire = __ATOMIC_ACQUIRE, memory_order_release = __ATOMIC_RELEASE, memory_order_acq_rel = __ATOMIC_ACQ_REL, memory_order_seq_cst = __ATOMIC_SEQ_CST } memory_order; /* * ISO C11 -- 7.17.7.2 The atomic_load generic functions * Integer width specific versions as supplement for: * * * #include * C atomic_load(volatile A *object); * C atomic_load_explicit(volatile A *object, memory_order order); * * The atomic_load interface doesn't return the loaded value, but instead * copies it to a specified address -- see comments at the MSVC version. * * Also, instead of generic functions, two versions are available: * for 32 bit fundamental integers, and for 64 bit ones. */ #define util_atomic_load_explicit32 __atomic_load #define util_atomic_load_explicit64 __atomic_load /* * ISO C11 -- 7.17.7.1 The atomic_store generic functions * Integer width specific versions as supplement for: * * #include * void atomic_store(volatile A *object, C desired); * void atomic_store_explicit(volatile A *object, C desired, * memory_order order); */ #define util_atomic_store_explicit32 __atomic_store_n #define util_atomic_store_explicit64 __atomic_store_n /* * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html * https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html * https://clang.llvm.org/docs/LanguageExtensions.html#builtin-functions */ #define util_bool_compare_and_swap32 __sync_bool_compare_and_swap #define util_bool_compare_and_swap64 __sync_bool_compare_and_swap #define util_fetch_and_add32 __sync_fetch_and_add #define util_fetch_and_add64 __sync_fetch_and_add #define util_fetch_and_sub32 __sync_fetch_and_sub #define util_fetch_and_sub64 __sync_fetch_and_sub #define util_fetch_and_and32 __sync_fetch_and_and #define util_fetch_and_and64 __sync_fetch_and_and #define util_fetch_and_or32 __sync_fetch_and_or #define util_fetch_and_or64 __sync_fetch_and_or #define util_synchronize __sync_synchronize #define util_popcount(value) ((unsigned char)__builtin_popcount(value)) #define util_popcount64(value) ((unsigned char)__builtin_popcountll(value)) #define util_lssb_index(value) ((unsigned char)__builtin_ctz(value)) #define util_lssb_index64(value) ((unsigned char)__builtin_ctzll(value)) #define util_mssb_index(value) ((unsigned char)(31 - __builtin_clz(value))) #define util_mssb_index64(value) ((unsigned char)(63 - __builtin_clzll(value))) #else /* ISO C11 -- 7.17.1.4 */ typedef enum { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst } memory_order; /* * ISO C11 -- 7.17.7.2 The atomic_load generic functions * Integer width specific versions as supplement for: * * * #include * C atomic_load(volatile A *object); * C atomic_load_explicit(volatile A *object, memory_order order); * * The atomic_load interface doesn't return the loaded value, but instead * copies it to a specified address. * The MSVC specific implementation needs to trigger a barrier (at least * compiler barrier) after the load from the volatile value. The actual load * from the volatile value itself is expected to be atomic. * * The actual isnterface here: * #include * void util_atomic_load32(volatile A *object, A *destination); * void util_atomic_load64(volatile A *object, A *destination); * void util_atomic_load_explicit32(volatile A *object, A *destination, * memory_order order); * void util_atomic_load_explicit64(volatile A *object, A *destination, * memory_order order); */ #ifndef _M_X64 #error MSVC ports of util_atomic_ only work on X86_64 #endif #if _MSC_VER > 1911 #error util_atomic_ utility functions not tested with this version of VC++ #error These utility functions are not future proof, as they are not #error based on publicly available documentation. #endif #define util_atomic_load_explicit(object, dest, order)\ do {\ COMPILE_ERROR_ON(order != memory_order_seq_cst &&\ order != memory_order_consume &&\ order != memory_order_acquire &&\ order != memory_order_relaxed);\ *dest = *object;\ if (order == memory_order_seq_cst ||\ order == memory_order_consume ||\ order == memory_order_acquire)\ _ReadWriteBarrier();\ } while (0) #define util_atomic_load_explicit32 util_atomic_load_explicit #define util_atomic_load_explicit64 util_atomic_load_explicit /* ISO C11 -- 7.17.7.1 The atomic_store generic functions */ #define util_atomic_store_explicit64(object, desired, order)\ do {\ COMPILE_ERROR_ON(order != memory_order_seq_cst &&\ order != memory_order_release &&\ order != memory_order_relaxed);\ if (order == memory_order_seq_cst) {\ _InterlockedExchange64(\ (volatile long long *)object, desired);\ } else {\ if (order == memory_order_release)\ _ReadWriteBarrier();\ *object = desired;\ }\ } while (0) #define util_atomic_store_explicit32(object, desired, order)\ do {\ COMPILE_ERROR_ON(order != memory_order_seq_cst &&\ order != memory_order_release &&\ order != memory_order_relaxed);\ if (order == memory_order_seq_cst) {\ _InterlockedExchange(\ (volatile long *)object, desired);\ } else {\ if (order == memory_order_release)\ _ReadWriteBarrier();\ *object = desired;\ }\ } while (0) /* * https://msdn.microsoft.com/en-us/library/hh977022.aspx */ static __inline int bool_compare_and_swap32_VC(volatile LONG *ptr, LONG oldval, LONG newval) { LONG old = InterlockedCompareExchange(ptr, newval, oldval); return (old == oldval); } static __inline int bool_compare_and_swap64_VC(volatile LONG64 *ptr, LONG64 oldval, LONG64 newval) { LONG64 old = InterlockedCompareExchange64(ptr, newval, oldval); return (old == oldval); } #define util_bool_compare_and_swap32(p, o, n)\ bool_compare_and_swap32_VC((LONG *)(p), (LONG)(o), (LONG)(n)) #define util_bool_compare_and_swap64(p, o, n)\ bool_compare_and_swap64_VC((LONG64 *)(p), (LONG64)(o), (LONG64)(n)) #define util_fetch_and_add32(ptr, value)\ InterlockedExchangeAdd((LONG *)(ptr), value) #define util_fetch_and_add64(ptr, value)\ InterlockedExchangeAdd64((LONG64 *)(ptr), value) #define util_fetch_and_sub32(ptr, value)\ InterlockedExchangeSubtract((LONG *)(ptr), value) #define util_fetch_and_sub64(ptr, value)\ InterlockedExchangeAdd64((LONG64 *)(ptr), -((LONG64)(value))) #define util_fetch_and_and32(ptr, value)\ InterlockedAnd((LONG *)(ptr), value) #define util_fetch_and_and64(ptr, value)\ InterlockedAnd64((LONG64 *)(ptr), value) #define util_fetch_and_or32(ptr, value)\ InterlockedOr((LONG *)(ptr), value) #define util_fetch_and_or64(ptr, value)\ InterlockedOr64((LONG64 *)(ptr), value) static __inline void util_synchronize(void) { MemoryBarrier(); } #define util_popcount(value) (unsigned char)__popcnt(value) #define util_popcount64(value) (unsigned char)__popcnt64(value) static __inline unsigned char util_lssb_index(int value) { unsigned long ret; _BitScanForward(&ret, value); return (unsigned char)ret; } static __inline unsigned char util_lssb_index64(long long value) { unsigned long ret; _BitScanForward64(&ret, value); return (unsigned char)ret; } static __inline unsigned char util_mssb_index(int value) { unsigned long ret; _BitScanReverse(&ret, value); return (unsigned char)ret; } static __inline unsigned char util_mssb_index64(long long value) { unsigned long ret; _BitScanReverse64(&ret, value); return (unsigned char)ret; } #endif /* ISO C11 -- 7.17.7 Operations on atomic types */ #define util_atomic_load32(object, dest)\ util_atomic_load_explicit32(object, dest, memory_order_seqcst) #define util_atomic_load64(object, dest)\ util_atomic_load_explicit64(object, dest, memory_order_seqcst) #define util_atomic_store32(object, desired)\ util_atomic_store_explicit32(object, desired, memory_order_seqcst) #define util_atomic_store64(object, desired)\ util_atomic_store_explicit64(object, desired, memory_order_seqcst) /* * util_get_printable_ascii -- convert non-printable ascii to dot '.' */ static inline char util_get_printable_ascii(char c) { return isprint((unsigned char)c) ? c : '.'; } char *util_concat_str(const char *s1, const char *s2); #if !defined(likely) #if defined(__GNUC__) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else #define likely(x) (!!(x)) #define unlikely(x) (!!(x)) #endif #endif #if defined(__CHECKER__) #define COMPILE_ERROR_ON(cond) #define ASSERT_COMPILE_ERROR_ON(cond) #elif defined(_MSC_VER) #define COMPILE_ERROR_ON(cond) C_ASSERT(!(cond)) /* XXX - can't be done with C_ASSERT() unless we have __builtin_constant_p() */ #define ASSERT_COMPILE_ERROR_ON(cond) #else #define COMPILE_ERROR_ON(cond) ((void)sizeof(char[(cond) ? -1 : 1])) #define ASSERT_COMPILE_ERROR_ON(cond) COMPILE_ERROR_ON(cond) #endif #ifndef _MSC_VER #define ATTR_CONSTRUCTOR __attribute__((constructor)) static #define ATTR_DESTRUCTOR __attribute__((destructor)) static #else #define ATTR_CONSTRUCTOR #define ATTR_DESTRUCTOR #endif #ifndef _MSC_VER #define CONSTRUCTOR(fun) ATTR_CONSTRUCTOR #else #ifdef __cplusplus #define CONSTRUCTOR(fun) \ void fun(); \ struct _##fun { \ _##fun() { \ fun(); \ } \ }; static _##fun foo; \ static #else #define CONSTRUCTOR(fun) \ MSVC_CONSTR(fun) \ static #endif #endif #ifdef __GNUC__ #define CHECK_FUNC_COMPATIBLE(func1, func2)\ COMPILE_ERROR_ON(!__builtin_types_compatible_p(typeof(func1),\ typeof(func2))) #else #define CHECK_FUNC_COMPATIBLE(func1, func2) do {} while (0) #endif /* __GNUC__ */ #ifdef __cplusplus } #endif #endif /* util.h */ pmdk-1.4.1/src/common/util_pmem.h000066400000000000000000000045361331545616200167110ustar00rootroot00000000000000/* * Copyright 2017-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * util_pmem.h -- internal definitions for pmem utils */ #ifndef PMDK_UTIL_PMEM_H #define PMDK_UTIL_PMEM_H 1 #ifdef __cplusplus extern "C" { #endif #include "libpmem.h" #include "out.h" /* * util_persist -- flush to persistence */ static inline void util_persist(int is_pmem, const void *addr, size_t len) { LOG(3, "is_pmem %d, addr %p, len %zu", is_pmem, addr, len); if (is_pmem) pmem_persist(addr, len); else if (pmem_msync(addr, len)) FATAL("!pmem_msync"); } /* * util_persist_auto -- flush to persistence */ static inline void util_persist_auto(int is_pmem, const void *addr, size_t len) { LOG(3, "is_pmem %d, addr %p, len %zu", is_pmem, addr, len); util_persist(is_pmem || pmem_is_pmem(addr, len), addr, len); } #ifdef __cplusplus } #endif #endif /* util_pmem.h */ pmdk-1.4.1/src/common/util_posix.c000066400000000000000000000073021331545616200171020ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * util_posix.c -- Abstraction layer for misc utilities (Posix implementation) */ #include #include #include #include #include #include #include "os.h" #include "out.h" /* pass through for Posix */ void util_strerror(int errnum, char *buff, size_t bufflen) { strerror_r(errnum, buff, bufflen); } /* * util_part_realpath -- get canonicalized absolute pathname * * As paths used in a poolset file have to be absolute (checked when parsing * a poolset file), here we only have to resolve symlinks. */ char * util_part_realpath(const char *path) { return realpath(path, NULL); } /* * util_compare_file_inodes -- compare device and inodes of two files; * this resolves hard links */ int util_compare_file_inodes(const char *path1, const char *path2) { struct stat sb1, sb2; if (os_stat(path1, &sb1)) { if (errno != ENOENT) { ERR("!stat failed for %s", path1); return -1; } LOG(1, "stat failed for %s", path1); errno = 0; return strcmp(path1, path2) != 0; } if (os_stat(path2, &sb2)) { if (errno != ENOENT) { ERR("!stat failed for %s", path2); return -1; } LOG(1, "stat failed for %s", path2); errno = 0; return strcmp(path1, path2) != 0; } return sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino; } /* * util_aligned_malloc -- allocate aligned memory */ void * util_aligned_malloc(size_t alignment, size_t size) { void *retval = NULL; errno = posix_memalign(&retval, alignment, size); return retval; } /* * util_aligned_free -- free allocated memory in util_aligned_malloc */ void util_aligned_free(void *ptr) { free(ptr); } /* * util_getexecname -- return name of current executable */ char * util_getexecname(char *path, size_t pathlen) { ssize_t cc; #ifdef __FreeBSD__ #include #include int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; cc = (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) ? -1 : (ssize_t)pathlen; #else cc = readlink("/proc/self/exe", path, pathlen); #endif if (cc == -1) strcpy(path, "unknown"); else path[cc] = '\0'; return path; } pmdk-1.4.1/src/common/util_windows.c000066400000000000000000000135341331545616200174360ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * util_windows.c -- misc utilities with OS-specific implementation */ #include #include #include #include "util.h" #include "out.h" #include "file.h" /* Windows CRT doesn't support all errors, add unmapped here */ #define ENOTSUP_STR "Operation not supported" #define ECANCELED_STR "Operation canceled" #define ENOERROR 0 #define ENOERROR_STR "Success" #define UNMAPPED_STR "Unmapped error" /* * util_strerror -- return string describing error number * * XXX: There are many other POSIX error codes that are not recognized by * strerror_s(), so eventually we may want to implement this in a similar * fashion as strsignal(). */ void util_strerror(int errnum, char *buff, size_t bufflen) { switch (errnum) { case ENOERROR: strcpy_s(buff, bufflen, ENOERROR_STR); break; case ENOTSUP: strcpy_s(buff, bufflen, ENOTSUP_STR); break; case ECANCELED: strcpy_s(buff, bufflen, ECANCELED_STR); break; default: if (strerror_s(buff, bufflen, errnum)) strcpy_s(buff, bufflen, UNMAPPED_STR); } } /* * util_part_realpath -- get canonicalized absolute pathname for a part file * * On Windows, paths cannot be symlinks and paths used in a poolset have to * be absolute (checked when parsing a poolset file), so we just return * the path. */ char * util_part_realpath(const char *path) { return strdup(path); } /* * util_compare_file_inodes -- compare device and inodes of two files */ int util_compare_file_inodes(const char *path1, const char *path2) { return strcmp(path1, path2) != 0; } /* * util_aligned_malloc -- allocate aligned memory */ void * util_aligned_malloc(size_t alignment, size_t size) { return _aligned_malloc(size, alignment); } /* * util_aligned_free -- free allocated memory in util_aligned_malloc */ void util_aligned_free(void *ptr) { _aligned_free(ptr); } /* * util_toUTF8 -- allocating conversion from wide char string to UTF8 */ char * util_toUTF8(const wchar_t *wstr) { int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr, -1, NULL, 0, NULL, NULL); if (size == 0) goto err; char *str = Malloc(size * sizeof(char)); if (str == NULL) goto out; if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr, -1, str, size, NULL, NULL) == 0) { Free(str); goto err; } out: return str; err: errno = EINVAL; return NULL; } /* * util_free_UTF8 -- free UTF8 string */ void util_free_UTF8(char *str) { Free(str); } /* * util_toUTF16 -- allocating conversion from UTF8 to wide char string */ wchar_t * util_toUTF16(const char *str) { int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, NULL, 0); if (size == 0) goto err; wchar_t *wstr = Malloc(size * sizeof(wchar_t)); if (wstr == NULL) goto out; if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, wstr, size) == 0) { Free(wstr); goto err; } out: return wstr; err: errno = EINVAL; return NULL; } /* * util_free_UTF16 -- free wide char string */ void util_free_UTF16(wchar_t *wstr) { Free(wstr); } /* * util_toUTF16_buff -- non-allocating conversion from UTF8 to wide char string * * The user responsible for supplying a large enough out buffer. */ int util_toUTF16_buff(const char *in, wchar_t *out, size_t out_size) { ASSERT(out != NULL); int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, in, -1, NULL, 0); if (size == 0 || out_size < size) goto err; if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, in, -1, out, size) == 0) goto err; return 0; err: errno = EINVAL; return -1; } /* * util_toUTF8_buff -- non-allocating conversion from wide char string to UTF8 * * The user responsible for supplying a large enough out buffer. */ int util_toUTF8_buff(const wchar_t *in, char *out, size_t out_size) { ASSERT(out != NULL); int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, -1, NULL, 0, NULL, NULL); if (size == 0 || out_size < size) goto err; if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, -1, out, size, NULL, NULL) == 0) goto err; return 0; err: errno = EINVAL; return -1; } /* * util_getexecname -- return name of current executable */ char * util_getexecname(char *path, size_t pathlen) { ssize_t cc; if ((cc = GetModuleFileNameA(NULL, path, (DWORD)pathlen)) == 0) strcpy(path, "unknown"); else path[cc] = '\0'; return path; } pmdk-1.4.1/src/common/uuid.c000066400000000000000000000063741331545616200156610ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * uuid.c -- uuid utilities */ #include #include #include #include "uuid.h" #include "out.h" /* * util_uuid_to_string -- generate a string form of the uuid */ int util_uuid_to_string(const uuid_t u, char *buf) { int len; /* size that is returned from sprintf call */ if (buf == NULL) { LOG(2, "invalid buffer for uuid string"); return -1; } if (u == NULL) { LOG(2, "invalid uuid structure"); return -1; } struct uuid *uuid = (struct uuid *)u; len = snprintf(buf, POOL_HDR_UUID_STR_LEN, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid->time_low, uuid->time_mid, uuid->time_hi_and_ver, uuid->clock_seq_hi, uuid->clock_seq_low, uuid->node[0], uuid->node[1], uuid->node[2], uuid->node[3], uuid->node[4], uuid->node[5]); if (len != POOL_HDR_UUID_STR_LEN - 1) { LOG(2, "snprintf(uuid)"); return -1; } return 0; } /* * util_uuid_from_string -- generate a binary form of the uuid * * uuid string read from /proc/sys/kernel/random/uuid. UUID string * format example: * f81d4fae-7dec-11d0-a765-00a0c91e6bf6 */ int util_uuid_from_string(const char *uuid, struct uuid *ud) { if (strlen(uuid) != 36) { LOG(2, "invalid uuid string"); return -1; } if (uuid[8] != '-' || uuid[13] != '-' || uuid[18] != '-' || uuid[23] != '-') { LOG(2, "invalid uuid string"); return -1; } int n = sscanf(uuid, "%08x-%04hx-%04hx-%02hhx%02hhx-" "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &ud->time_low, &ud->time_mid, &ud->time_hi_and_ver, &ud->clock_seq_hi, &ud->clock_seq_low, &ud->node[0], &ud->node[1], &ud->node[2], &ud->node[3], &ud->node[4], &ud->node[5]); if (n != 11) { LOG(2, "sscanf(uuid)"); return -1; } return 0; } pmdk-1.4.1/src/common/uuid.h000066400000000000000000000050371331545616200156610ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * uuid.h -- internal definitions for uuid module */ #ifndef PMDK_UUID_H #define PMDK_UUID_H 1 #include #include /* * Structure for binary version of uuid. From RFC4122, * https://tools.ietf.org/html/rfc4122 */ struct uuid { uint32_t time_low; uint16_t time_mid; uint16_t time_hi_and_ver; uint8_t clock_seq_hi; uint8_t clock_seq_low; uint8_t node[6]; }; #define POOL_HDR_UUID_LEN 16 /* uuid byte length */ #define POOL_HDR_UUID_STR_LEN 37 /* uuid string length */ #define POOL_HDR_UUID_GEN_FILE "/proc/sys/kernel/random/uuid" typedef unsigned char uuid_t[POOL_HDR_UUID_LEN]; /* 16 byte binary uuid value */ int util_uuid_generate(uuid_t uuid); int util_uuid_to_string(const uuid_t u, char *buf); int util_uuid_from_string(const char uuid[POOL_HDR_UUID_STR_LEN], struct uuid *ud); /* * uuidcmp -- compare two uuids */ static inline int uuidcmp(const uuid_t uuid1, const uuid_t uuid2) { return memcmp(uuid1, uuid2, POOL_HDR_UUID_LEN); } #endif pmdk-1.4.1/src/common/uuid_freebsd.c000066400000000000000000000037031331545616200173440ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * uuid_freebsd.c -- FreeBSD-specific implementation for UUID generation */ #include "uuid.h" /* XXX Can't include because it also defines uuid_t */ void uuid_generate(uuid_t); /* * util_uuid_generate -- generate a uuid * * Uses the available FreeBSD uuid_generate library function. */ int util_uuid_generate(uuid_t uuid) { uuid_generate(uuid); return 0; } pmdk-1.4.1/src/common/uuid_linux.c000066400000000000000000000047661331545616200171030ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * uuid_linux.c -- pool set utilities with OS-specific implementation */ #include #include #include #include "uuid.h" #include "os.h" #include "out.h" /* * util_uuid_generate -- generate a uuid * * This function reads the uuid string from /proc/sys/kernel/random/uuid * It converts this string into the binary uuid format as specified in * https://www.ietf.org/rfc/rfc4122.txt */ int util_uuid_generate(uuid_t uuid) { char uu[POOL_HDR_UUID_STR_LEN]; int fd = os_open(POOL_HDR_UUID_GEN_FILE, O_RDONLY); if (fd < 0) { /* Fatal error */ LOG(2, "!open(uuid)"); return -1; } ssize_t num = read(fd, uu, POOL_HDR_UUID_STR_LEN); if (num < POOL_HDR_UUID_STR_LEN) { /* Fatal error */ LOG(2, "!read(uuid)"); os_close(fd); return -1; } os_close(fd); uu[POOL_HDR_UUID_STR_LEN - 1] = '\0'; int ret = util_uuid_from_string(uu, (struct uuid *)uuid); if (ret < 0) return ret; return 0; } pmdk-1.4.1/src/common/uuid_windows.c000066400000000000000000000036011331545616200174210ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * uuid_windows.c -- pool set utilities with OS-specific implementation */ #include "uuid.h" #include "out.h" /* * util_uuid_generate -- generate a uuid */ int util_uuid_generate(uuid_t uuid) { HRESULT res = CoCreateGuid((GUID *)(uuid)); if (res != S_OK) { ERR("CoCreateGuid"); return -1; } return 0; } pmdk-1.4.1/src/common/valgrind/000077500000000000000000000000001331545616200163435ustar00rootroot00000000000000pmdk-1.4.1/src/common/valgrind/.cstyleignore000066400000000000000000000000631331545616200210520ustar00rootroot00000000000000drd.h helgrind.h memcheck.h pmemcheck.h valgrind.h pmdk-1.4.1/src/common/valgrind/README000066400000000000000000000001331331545616200172200ustar00rootroot00000000000000Files in this directory were imported from Valgrind 3.12: https://github.com/pmem/valgrind pmdk-1.4.1/src/common/valgrind/drd.h000066400000000000000000000547061331545616200173010ustar00rootroot00000000000000/* ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (drd.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of DRD, a Valgrind tool for verification of multithreaded programs. Copyright (C) 2006-2015 Bart Van Assche . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (drd.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ #ifndef __VALGRIND_DRD_H #define __VALGRIND_DRD_H #include "valgrind.h" /** Obtain the thread ID assigned by Valgrind's core. */ #define DRD_GET_VALGRIND_THREADID \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID, \ 0, 0, 0, 0, 0) /** Obtain the thread ID assigned by DRD. */ #define DRD_GET_DRD_THREADID \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__DRD_GET_DRD_THREAD_ID, \ 0, 0, 0, 0, 0) /** Tell DRD not to complain about data races for the specified variable. */ #define DRD_IGNORE_VAR(x) ANNOTATE_BENIGN_RACE_SIZED(&(x), sizeof(x), "") /** Tell DRD to no longer ignore data races for the specified variable. */ #define DRD_STOP_IGNORING_VAR(x) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_FINISH_SUPPRESSION, \ &(x), sizeof(x), 0, 0, 0) /** * Tell DRD to trace all memory accesses for the specified variable * until the memory that was allocated for the variable is freed. */ #define DRD_TRACE_VAR(x) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_TRACE_ADDR, \ &(x), sizeof(x), 0, 0, 0) /** * Tell DRD to stop tracing memory accesses for the specified variable. */ #define DRD_STOP_TRACING_VAR(x) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_STOP_TRACE_ADDR, \ &(x), sizeof(x), 0, 0, 0) /** * @defgroup RaceDetectionAnnotations Data race detection annotations. * * @see See also the source file producer-consumer. */ #define ANNOTATE_PCQ_CREATE(pcq) do { } while(0) /** Tell DRD that a FIFO queue has been destroyed. */ #define ANNOTATE_PCQ_DESTROY(pcq) do { } while(0) /** * Tell DRD that an element has been added to the FIFO queue at address pcq. */ #define ANNOTATE_PCQ_PUT(pcq) do { } while(0) /** * Tell DRD that an element has been removed from the FIFO queue at address pcq, * and that DRD should insert a happens-before relationship between the memory * accesses that occurred before the corresponding ANNOTATE_PCQ_PUT(pcq) * annotation and the memory accesses after this annotation. Correspondence * between PUT and GET annotations happens in FIFO order. Since locking * of the queue is needed anyway to add elements to or to remove elements from * the queue, for DRD all four FIFO annotations are defined as no-ops. */ #define ANNOTATE_PCQ_GET(pcq) do { } while(0) /** * Tell DRD that data races at the specified address are expected and must not * be reported. */ #define ANNOTATE_BENIGN_RACE(addr, descr) \ ANNOTATE_BENIGN_RACE_SIZED(addr, sizeof(*addr), descr) /* Same as ANNOTATE_BENIGN_RACE(addr, descr), but applies to the memory range [addr, addr + size). */ #define ANNOTATE_BENIGN_RACE_SIZED(addr, size, descr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_SUPPRESSION, \ addr, size, 0, 0, 0) /** Tell DRD to ignore all reads performed by the current thread. */ #define ANNOTATE_IGNORE_READS_BEGIN() \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_RECORD_LOADS, \ 0, 0, 0, 0, 0); /** Tell DRD to no longer ignore the reads performed by the current thread. */ #define ANNOTATE_IGNORE_READS_END() \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_RECORD_LOADS, \ 1, 0, 0, 0, 0); /** Tell DRD to ignore all writes performed by the current thread. */ #define ANNOTATE_IGNORE_WRITES_BEGIN() \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_RECORD_STORES, \ 0, 0, 0, 0, 0) /** Tell DRD to no longer ignore the writes performed by the current thread. */ #define ANNOTATE_IGNORE_WRITES_END() \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_RECORD_STORES, \ 1, 0, 0, 0, 0) /** Tell DRD to ignore all memory accesses performed by the current thread. */ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ do { ANNOTATE_IGNORE_READS_BEGIN(); ANNOTATE_IGNORE_WRITES_BEGIN(); } while(0) /** * Tell DRD to no longer ignore the memory accesses performed by the current * thread. */ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ do { ANNOTATE_IGNORE_READS_END(); ANNOTATE_IGNORE_WRITES_END(); } while(0) /** * Tell DRD that size bytes starting at addr has been allocated by a custom * memory allocator. */ #define ANNOTATE_NEW_MEMORY(addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_CLEAN_MEMORY, \ addr, size, 0, 0, 0) /** Ask DRD to report every access to the specified address. */ #define ANNOTATE_TRACE_MEMORY(addr) DRD_TRACE_VAR(*(char*)(addr)) /** * Tell DRD to assign the specified name to the current thread. This name will * be used in error messages printed by DRD. */ #define ANNOTATE_THREAD_NAME(name) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_SET_THREAD_NAME, \ name, 0, 0, 0, 0) /*@}*/ /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ enum { /* Ask the DRD tool to discard all information about memory accesses */ /* and client objects for the specified range. This client request is */ /* binary compatible with the similarly named Helgrind client request. */ VG_USERREQ__DRD_CLEAN_MEMORY = VG_USERREQ_TOOL_BASE('H','G'), /* args: Addr, SizeT. */ /* Ask the DRD tool the thread ID assigned by Valgrind. */ VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID = VG_USERREQ_TOOL_BASE('D','R'), /* args: none. */ /* Ask the DRD tool the thread ID assigned by DRD. */ VG_USERREQ__DRD_GET_DRD_THREAD_ID, /* args: none. */ /* To tell the DRD tool to suppress data race detection on the */ /* specified address range. */ VG_USERREQ__DRD_START_SUPPRESSION, /* args: start address, size in bytes */ /* To tell the DRD tool no longer to suppress data race detection on */ /* the specified address range. */ VG_USERREQ__DRD_FINISH_SUPPRESSION, /* args: start address, size in bytes */ /* To ask the DRD tool to trace all accesses to the specified range. */ VG_USERREQ__DRD_START_TRACE_ADDR, /* args: Addr, SizeT. */ /* To ask the DRD tool to stop tracing accesses to the specified range. */ VG_USERREQ__DRD_STOP_TRACE_ADDR, /* args: Addr, SizeT. */ /* Tell DRD whether or not to record memory loads in the calling thread. */ VG_USERREQ__DRD_RECORD_LOADS, /* args: Bool. */ /* Tell DRD whether or not to record memory stores in the calling thread. */ VG_USERREQ__DRD_RECORD_STORES, /* args: Bool. */ /* Set the name of the thread that performs this client request. */ VG_USERREQ__DRD_SET_THREAD_NAME, /* args: null-terminated character string. */ /* Tell DRD that a DRD annotation has not yet been implemented. */ VG_USERREQ__DRD_ANNOTATION_UNIMP, /* args: char*. */ /* Tell DRD that a user-defined semaphore synchronization object * is about to be created. */ VG_USERREQ__DRD_ANNOTATE_SEM_INIT_PRE, /* args: Addr, UInt value. */ /* Tell DRD that a user-defined semaphore synchronization object * has been destroyed. */ VG_USERREQ__DRD_ANNOTATE_SEM_DESTROY_POST, /* args: Addr. */ /* Tell DRD that a user-defined semaphore synchronization * object is going to be acquired (semaphore wait). */ VG_USERREQ__DRD_ANNOTATE_SEM_WAIT_PRE, /* args: Addr. */ /* Tell DRD that a user-defined semaphore synchronization * object has been acquired (semaphore wait). */ VG_USERREQ__DRD_ANNOTATE_SEM_WAIT_POST, /* args: Addr. */ /* Tell DRD that a user-defined semaphore synchronization * object is about to be released (semaphore post). */ VG_USERREQ__DRD_ANNOTATE_SEM_POST_PRE, /* args: Addr. */ /* Tell DRD to ignore the inter-thread ordering introduced by a mutex. */ VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING, /* args: Addr. */ /* Tell DRD that a user-defined reader-writer synchronization object * has been created. */ VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE = VG_USERREQ_TOOL_BASE('H','G') + 256 + 14, /* args: Addr. */ /* Tell DRD that a user-defined reader-writer synchronization object * is about to be destroyed. */ VG_USERREQ__DRD_ANNOTATE_RWLOCK_DESTROY = VG_USERREQ_TOOL_BASE('H','G') + 256 + 15, /* args: Addr. */ /* Tell DRD that a lock on a user-defined reader-writer synchronization * object has been acquired. */ VG_USERREQ__DRD_ANNOTATE_RWLOCK_ACQUIRED = VG_USERREQ_TOOL_BASE('H','G') + 256 + 17, /* args: Addr, Int is_rw. */ /* Tell DRD that a lock on a user-defined reader-writer synchronization * object is about to be released. */ VG_USERREQ__DRD_ANNOTATE_RWLOCK_RELEASED = VG_USERREQ_TOOL_BASE('H','G') + 256 + 18, /* args: Addr, Int is_rw. */ /* Tell DRD that a Helgrind annotation has not yet been implemented. */ VG_USERREQ__HELGRIND_ANNOTATION_UNIMP = VG_USERREQ_TOOL_BASE('H','G') + 256 + 32, /* args: char*. */ /* Tell DRD to insert a happens-before annotation. */ VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE = VG_USERREQ_TOOL_BASE('H','G') + 256 + 33, /* args: Addr. */ /* Tell DRD to insert a happens-after annotation. */ VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER = VG_USERREQ_TOOL_BASE('H','G') + 256 + 34, /* args: Addr. */ }; /** * @addtogroup RaceDetectionAnnotations */ /*@{*/ #ifdef __cplusplus /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racy reads. Instead of doing ANNOTATE_IGNORE_READS_BEGIN(); ... = x; ANNOTATE_IGNORE_READS_END(); one can use ... = ANNOTATE_UNPROTECTED_READ(x); */ template inline T ANNOTATE_UNPROTECTED_READ(const volatile T& x) { ANNOTATE_IGNORE_READS_BEGIN(); const T result = x; ANNOTATE_IGNORE_READS_END(); return result; } /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ namespace { \ static class static_var##_annotator \ { \ public: \ static_var##_annotator() \ { \ ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \ #static_var ": " description); \ } \ } the_##static_var##_annotator; \ } #endif /*@}*/ #endif /* __VALGRIND_DRD_H */ pmdk-1.4.1/src/common/valgrind/helgrind.h000066400000000000000000001102601331545616200203100ustar00rootroot00000000000000/* ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (helgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of Helgrind, a Valgrind tool for detecting errors in threaded programs. Copyright (C) 2007-2015 OpenWorks LLP info@open-works.co.uk Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (helgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ #ifndef __HELGRIND_H #define __HELGRIND_H #include "valgrind.h" /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__HG_CLEAN_MEMORY = VG_USERREQ_TOOL_BASE('H','G'), /* The rest are for Helgrind's internal use. Not for end-user use. Do not use them unless you are a Valgrind developer. */ /* Notify the tool what this thread's pthread_t is. */ _VG_USERREQ__HG_SET_MY_PTHREAD_T = VG_USERREQ_TOOL_BASE('H','G') + 256, _VG_USERREQ__HG_PTH_API_ERROR, /* char*, int */ _VG_USERREQ__HG_PTHREAD_JOIN_POST, /* pthread_t of quitter */ _VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, /* pth_mx_t*, long mbRec */ _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, /* pth_mx_t*, long isInit */ _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, /* pth_mx_t* */ _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, /* pth_mx_t* */ _VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE, /* void*, long isTryLock */ _VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST, /* void* */ _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE, /* pth_cond_t* */ _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE, /* pth_cond_t* */ _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, /* pth_cond_t*, pth_mx_t* */ _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, /* pth_cond_t*, pth_mx_t* */ _VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE, /* pth_cond_t*, long isInit */ _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, /* pth_rwlk_t* */ _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, /* pth_rwlk_t* */ _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, /* pth_rwlk_t*, long isW */ _VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED, /* void*, long isW */ _VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED, /* void* */ _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, /* pth_rwlk_t* */ _VG_USERREQ__HG_POSIX_SEM_INIT_POST, /* sem_t*, ulong value */ _VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, /* sem_t* */ _VG_USERREQ__HG_POSIX_SEM_RELEASED, /* void* */ _VG_USERREQ__HG_POSIX_SEM_ACQUIRED, /* void* */ _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE, /* pth_bar_t*, ulong, ulong */ _VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE, /* pth_bar_t* */ _VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, /* pth_bar_t* */ _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE, /* pth_slk_t* */ _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST, /* pth_slk_t* */ _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE, /* pth_slk_t* */ _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST, /* pth_slk_t* */ _VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE, /* pth_slk_t* */ _VG_USERREQ__HG_CLIENTREQ_UNIMP, /* char* */ _VG_USERREQ__HG_USERSO_SEND_PRE, /* arbitrary UWord SO-tag */ _VG_USERREQ__HG_USERSO_RECV_POST, /* arbitrary UWord SO-tag */ _VG_USERREQ__HG_USERSO_FORGET_ALL, /* arbitrary UWord SO-tag */ _VG_USERREQ__HG_RESERVED2, /* Do not use */ _VG_USERREQ__HG_RESERVED3, /* Do not use */ _VG_USERREQ__HG_RESERVED4, /* Do not use */ _VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED, /* Addr a, ulong len */ _VG_USERREQ__HG_ARANGE_MAKE_TRACKED, /* Addr a, ulong len */ _VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE, /* pth_bar_t*, ulong */ _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK, /* Addr start_of_block */ _VG_USERREQ__HG_PTHREAD_COND_INIT_POST, /* pth_cond_t*, pth_cond_attr_t*/ _VG_USERREQ__HG_GNAT_MASTER_HOOK, /* void*d,void*m,Word ml */ _VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK, /* void*s,Word ml */ _VG_USERREQ__HG_GET_ABITS, /* Addr a,Addr abits, ulong len */ _VG_USERREQ__HG_PTHREAD_CREATE_BEGIN, _VG_USERREQ__HG_PTHREAD_CREATE_END, _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, /* pth_mx_t*,long isTryLock */ _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, /* pth_mx_t *,long tookLock */ _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, /* pth_rwlk_t*,long isW,long */ _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE, /* pth_rwlk_t* */ _VG_USERREQ__HG_POSIX_SEM_POST_PRE, /* sem_t* */ _VG_USERREQ__HG_POSIX_SEM_POST_POST, /* sem_t* */ _VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, /* sem_t* */ _VG_USERREQ__HG_POSIX_SEM_WAIT_POST, /* sem_t*, long tookLock */ _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST, /* pth_cond_t* */ _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,/* pth_cond_t* */ _VG_USERREQ__HG_RTLD_BIND_GUARD, /* int flags */ _VG_USERREQ__HG_RTLD_BIND_CLEAR /* int flags */ } Vg_TCheckClientRequest; /*----------------------------------------------------------------*/ /*--- ---*/ /*--- Implementation-only facilities. Not for end-user use. ---*/ /*--- For end-user facilities see below (the next section in ---*/ /*--- this file.) ---*/ /*--- ---*/ /*----------------------------------------------------------------*/ /* Do a client request. These are macros rather than a functions so as to avoid having an extra frame in stack traces. NB: these duplicate definitions in hg_intercepts.c. But here, we have to make do with weaker typing (no definition of Word etc) and no assertions, whereas in helgrind.h we can use those facilities. Obviously it's important the two sets of definitions are kept in sync. The commented-out asserts should actually hold, but unfortunately they can't be allowed to be visible here, because that would require the end-user code to #include . */ #define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \ do { \ long int _arg1; \ /* assert(sizeof(_ty1F) == sizeof(long int)); */ \ _arg1 = (long int)(_arg1F); \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ (_creqF), \ _arg1, 0,0,0,0); \ } while (0) #define DO_CREQ_W_W(_resF, _dfltF, _creqF, _ty1F,_arg1F) \ do { \ long int _arg1; \ /* assert(sizeof(_ty1F) == sizeof(long int)); */ \ _arg1 = (long int)(_arg1F); \ _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR( \ (_dfltF), \ (_creqF), \ _arg1, 0,0,0,0); \ _resF = _qzz_res; \ } while (0) #define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \ do { \ long int _arg1, _arg2; \ /* assert(sizeof(_ty1F) == sizeof(long int)); */ \ /* assert(sizeof(_ty2F) == sizeof(long int)); */ \ _arg1 = (long int)(_arg1F); \ _arg2 = (long int)(_arg2F); \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ (_creqF), \ _arg1,_arg2,0,0,0); \ } while (0) #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \ _ty2F,_arg2F, _ty3F, _arg3F) \ do { \ long int _arg1, _arg2, _arg3; \ /* assert(sizeof(_ty1F) == sizeof(long int)); */ \ /* assert(sizeof(_ty2F) == sizeof(long int)); */ \ /* assert(sizeof(_ty3F) == sizeof(long int)); */ \ _arg1 = (long int)(_arg1F); \ _arg2 = (long int)(_arg2F); \ _arg3 = (long int)(_arg3F); \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ (_creqF), \ _arg1,_arg2,_arg3,0,0); \ } while (0) #define DO_CREQ_W_WWW(_resF, _dfltF, _creqF, _ty1F,_arg1F, \ _ty2F,_arg2F, _ty3F, _arg3F) \ do { \ long int _qzz_res; \ long int _arg1, _arg2, _arg3; \ /* assert(sizeof(_ty1F) == sizeof(long int)); */ \ _arg1 = (long int)(_arg1F); \ _arg2 = (long int)(_arg2F); \ _arg3 = (long int)(_arg3F); \ _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR( \ (_dfltF), \ (_creqF), \ _arg1,_arg2,_arg3,0,0); \ _resF = _qzz_res; \ } while (0) #define _HG_CLIENTREQ_UNIMP(_qzz_str) \ DO_CREQ_v_W(_VG_USERREQ__HG_CLIENTREQ_UNIMP, \ (char*),(_qzz_str)) /*----------------------------------------------------------------*/ /*--- ---*/ /*--- Helgrind-native requests. These allow access to ---*/ /*--- the same set of annotation primitives that are used ---*/ /*--- to build the POSIX pthread wrappers. ---*/ /*--- ---*/ /*----------------------------------------------------------------*/ /* ---------------------------------------------------------- For describing ordinary mutexes (non-rwlocks). For rwlock descriptions see ANNOTATE_RWLOCK_* below. ---------------------------------------------------------- */ /* Notify here immediately after mutex creation. _mbRec == 0 for a non-recursive mutex, 1 for a recursive mutex. */ #define VALGRIND_HG_MUTEX_INIT_POST(_mutex, _mbRec) \ DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, \ void*,(_mutex), long,(_mbRec)) /* Notify here immediately before mutex acquisition. _isTryLock == 0 for a normal acquisition, 1 for a "try" style acquisition. */ #define VALGRIND_HG_MUTEX_LOCK_PRE(_mutex, _isTryLock) \ DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE, \ void*,(_mutex), long,(_isTryLock)) /* Notify here immediately after a successful mutex acquisition. */ #define VALGRIND_HG_MUTEX_LOCK_POST(_mutex) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST, \ void*,(_mutex)) /* Notify here immediately before a mutex release. */ #define VALGRIND_HG_MUTEX_UNLOCK_PRE(_mutex) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, \ void*,(_mutex)) /* Notify here immediately after a mutex release. */ #define VALGRIND_HG_MUTEX_UNLOCK_POST(_mutex) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, \ void*,(_mutex)) /* Notify here immediately before mutex destruction. */ #define VALGRIND_HG_MUTEX_DESTROY_PRE(_mutex) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, \ void*,(_mutex)) /* ---------------------------------------------------------- For describing semaphores. ---------------------------------------------------------- */ /* Notify here immediately after semaphore creation. */ #define VALGRIND_HG_SEM_INIT_POST(_sem, _value) \ DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, \ void*, (_sem), unsigned long, (_value)) /* Notify here immediately after a semaphore wait (an acquire-style operation) */ #define VALGRIND_HG_SEM_WAIT_POST(_sem) \ DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_ACQUIRED, \ void*,(_sem)) /* Notify here immediately before semaphore post (a release-style operation) */ #define VALGRIND_HG_SEM_POST_PRE(_sem) \ DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_RELEASED, \ void*,(_sem)) /* Notify here immediately before semaphore destruction. */ #define VALGRIND_HG_SEM_DESTROY_PRE(_sem) \ DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, \ void*, (_sem)) /* ---------------------------------------------------------- For describing barriers. ---------------------------------------------------------- */ /* Notify here immediately before barrier creation. _count is the capacity. _resizable == 0 means the barrier may not be resized, 1 means it may be. */ #define VALGRIND_HG_BARRIER_INIT_PRE(_bar, _count, _resizable) \ DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE, \ void*,(_bar), \ unsigned long,(_count), \ unsigned long,(_resizable)) /* Notify here immediately before arrival at a barrier. */ #define VALGRIND_HG_BARRIER_WAIT_PRE(_bar) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE, \ void*,(_bar)) /* Notify here immediately before a resize (change of barrier capacity). If _newcount >= the existing capacity, then there is no change in the state of any threads waiting at the barrier. If _newcount < the existing capacity, and >= _newcount threads are currently waiting at the barrier, then this notification is considered to also have the effect of telling the checker that all waiting threads have now moved past the barrier. (I can't think of any other sane semantics.) */ #define VALGRIND_HG_BARRIER_RESIZE_PRE(_bar, _newcount) \ DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE, \ void*,(_bar), \ unsigned long,(_newcount)) /* Notify here immediately before barrier destruction. */ #define VALGRIND_HG_BARRIER_DESTROY_PRE(_bar) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, \ void*,(_bar)) /* ---------------------------------------------------------- For describing memory ownership changes. ---------------------------------------------------------- */ /* Clean memory state. This makes Helgrind forget everything it knew about the specified memory range. Effectively this announces that the specified memory range now "belongs" to the calling thread, so that: (1) the calling thread can access it safely without synchronisation, and (2) all other threads must sync with this one to access it safely. This is particularly useful for memory allocators that wish to recycle memory. */ #define VALGRIND_HG_CLEAN_MEMORY(_qzz_start, _qzz_len) \ DO_CREQ_v_WW(VG_USERREQ__HG_CLEAN_MEMORY, \ void*,(_qzz_start), \ unsigned long,(_qzz_len)) /* The same, but for the heap block starting at _qzz_blockstart. This allows painting when we only know the address of an object, but not its size, which is sometimes the case in C++ code involving inheritance, and in which RTTI is not, for whatever reason, available. Returns the number of bytes painted, which can be zero for a zero-sized block. Hence, return values >= 0 indicate success (the block was found), and the value -1 indicates block not found, and -2 is returned when not running on Helgrind. */ #define VALGRIND_HG_CLEAN_MEMORY_HEAPBLOCK(_qzz_blockstart) \ (__extension__ \ ({long int _npainted; \ DO_CREQ_W_W(_npainted, (-2)/*default*/, \ _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK, \ void*,(_qzz_blockstart)); \ _npainted; \ })) /* ---------------------------------------------------------- For error control. ---------------------------------------------------------- */ /* Tell H that an address range is not to be "tracked" until further notice. This puts it in the NOACCESS state, in which case we ignore all reads and writes to it. Useful for ignoring ranges of memory where there might be races we don't want to see. If the memory is subsequently reallocated via malloc/new/stack allocation, then it is put back in the trackable state. Hence it is safe in the situation where checking is disabled, the containing area is deallocated and later reallocated for some other purpose. */ #define VALGRIND_HG_DISABLE_CHECKING(_qzz_start, _qzz_len) \ DO_CREQ_v_WW(_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED, \ void*,(_qzz_start), \ unsigned long,(_qzz_len)) /* And put it back into the normal "tracked" state, that is, make it once again subject to the normal race-checking machinery. This puts it in the same state as new memory allocated by this thread -- that is, basically owned exclusively by this thread. */ #define VALGRIND_HG_ENABLE_CHECKING(_qzz_start, _qzz_len) \ DO_CREQ_v_WW(_VG_USERREQ__HG_ARANGE_MAKE_TRACKED, \ void*,(_qzz_start), \ unsigned long,(_qzz_len)) /* Checks the accessibility bits for addresses [zza..zza+zznbytes-1]. If zzabits array is provided, copy the accessibility bits in zzabits. Return values: -2 if not running on helgrind -1 if any parts of zzabits is not addressable >= 0 : success. When success, it returns the nr of addressable bytes found. So, to check that a whole range is addressable, check VALGRIND_HG_GET_ABITS(addr,NULL,len) == len In addition, if you want to examine the addressability of each byte of the range, you need to provide a non NULL ptr as second argument, pointing to an array of unsigned char of length len. Addressable bytes are indicated with 0xff. Non-addressable bytes are indicated with 0x00. */ #define VALGRIND_HG_GET_ABITS(zza,zzabits,zznbytes) \ (__extension__ \ ({long int _res; \ DO_CREQ_W_WWW(_res, (-2)/*default*/, \ _VG_USERREQ__HG_GET_ABITS, \ void*,(zza), void*,(zzabits), \ unsigned long,(zznbytes)); \ _res; \ })) /*----------------------------------------------------------------*/ /*--- ---*/ /*--- ThreadSanitizer-compatible requests ---*/ /*--- (mostly unimplemented) ---*/ /*--- ---*/ /*----------------------------------------------------------------*/ /* A quite-broad set of annotations, as used in the ThreadSanitizer project. This implementation aims to be a (source-level) compatible implementation of the macros defined in: http://code.google.com/p/data-race-test/source /browse/trunk/dynamic_annotations/dynamic_annotations.h (some of the comments below are taken from the above file) The implementation here is very incomplete, and intended as a starting point. Many of the macros are unimplemented. Rather than allowing unimplemented macros to silently do nothing, they cause an assertion. Intention is to implement them on demand. The major use of these macros is to make visible to race detectors, the behaviour (effects) of user-implemented synchronisation primitives, that the detectors could not otherwise deduce from the normal observation of pthread etc calls. Some of the macros are no-ops in Helgrind. That's because Helgrind is a pure happens-before detector, whereas ThreadSanitizer uses a hybrid lockset and happens-before scheme, which requires more accurate annotations for correct operation. The macros are listed in the same order as in dynamic_annotations.h (URL just above). I should point out that I am less than clear about the intended semantics of quite a number of them. Comments and clarifications welcomed! */ /* ---------------------------------------------------------------- These four allow description of user-level condition variables, apparently in the style of POSIX's pthread_cond_t. Currently unimplemented and will assert. ---------------------------------------------------------------- */ /* Report that wait on the condition variable at address CV has succeeded and the lock at address LOCK is now held. CV and LOCK are completely arbitrary memory addresses which presumably mean something to the application, but are meaningless to Helgrind. */ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_LOCK_WAIT") /* Report that wait on the condition variable at CV has succeeded. Variant w/o lock. */ #define ANNOTATE_CONDVAR_WAIT(cv) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_WAIT") /* Report that we are about to signal on the condition variable at address CV. */ #define ANNOTATE_CONDVAR_SIGNAL(cv) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_SIGNAL") /* Report that we are about to signal_all on the condition variable at CV. */ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_SIGNAL_ALL") /* ---------------------------------------------------------------- Create completely arbitrary happens-before edges between threads. If threads T1 .. Tn all do ANNOTATE_HAPPENS_BEFORE(obj) and later (w.r.t. some notional global clock for the computation) thread Tm does ANNOTATE_HAPPENS_AFTER(obj), then Helgrind will regard all memory accesses done by T1 .. Tn before the ..BEFORE.. call as happening-before all memory accesses done by Tm after the ..AFTER.. call. Hence Helgrind won't complain about races if Tm's accesses afterwards are to the same locations as accesses before by any of T1 .. Tn. OBJ is a machine word (unsigned long, or void*), is completely arbitrary, and denotes the identity of some synchronisation object you're modelling. You must do the _BEFORE call just before the real sync event on the signaller's side, and _AFTER just after the real sync event on the waiter's side. If none of the rest of these macros make sense to you, at least take the time to understand these two. They form the very essence of describing arbitrary inter-thread synchronisation events to Helgrind. You can get a long way just with them alone. See also, extensive discussion on semantics of this in https://bugs.kde.org/show_bug.cgi?id=243935 ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(obj) is interim until such time as bug 243935 is fully resolved. It instructs Helgrind to forget about any ANNOTATE_HAPPENS_BEFORE calls on the specified object, in effect putting it back in its original state. Once in that state, a use of ANNOTATE_HAPPENS_AFTER on it has no effect on the calling thread. An implementation may optionally release resources it has associated with 'obj' when ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(obj) happens. Users are recommended to use ANNOTATE_HAPPENS_BEFORE_FORGET_ALL to indicate when a synchronisation object is no longer needed, so as to avoid potential indefinite resource leaks. ---------------------------------------------------------------- */ #define ANNOTATE_HAPPENS_BEFORE(obj) \ DO_CREQ_v_W(_VG_USERREQ__HG_USERSO_SEND_PRE, void*,(obj)) #define ANNOTATE_HAPPENS_AFTER(obj) \ DO_CREQ_v_W(_VG_USERREQ__HG_USERSO_RECV_POST, void*,(obj)) #define ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(obj) \ DO_CREQ_v_W(_VG_USERREQ__HG_USERSO_FORGET_ALL, void*,(obj)) /* ---------------------------------------------------------------- Memory publishing. The TSan sources say: Report that the bytes in the range [pointer, pointer+size) are about to be published safely. The race checker will create a happens-before arc from the call ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to subsequent accesses to this memory. I'm not sure I understand what this means exactly, nor whether it is relevant for a pure h-b detector. Leaving unimplemented for now. ---------------------------------------------------------------- */ #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_PUBLISH_MEMORY_RANGE") /* DEPRECATED. Don't use it. */ /* #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) */ /* DEPRECATED. Don't use it. */ /* #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) */ /* ---------------------------------------------------------------- TSan sources say: Instruct the tool to create a happens-before arc between MU->Unlock() and MU->Lock(). This annotation may slow down the race detector; normally it is used only when it would be difficult to annotate each of the mutex's critical sections individually using the annotations above. If MU is a posix pthread_mutex_t then Helgrind will do this anyway. In any case, leave as unimp for now. I'm unsure about the intended behaviour. ---------------------------------------------------------------- */ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX") /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */ /* #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) */ /* ---------------------------------------------------------------- TSan sources say: Annotations useful when defining memory allocators, or when memory that was protected in one way starts to be protected in another. Report that a new memory at "address" of size "size" has been allocated. This might be used when the memory has been retrieved from a free list and is about to be reused, or when a the locking discipline for a variable changes. AFAICS this is the same as VALGRIND_HG_CLEAN_MEMORY. ---------------------------------------------------------------- */ #define ANNOTATE_NEW_MEMORY(address, size) \ VALGRIND_HG_CLEAN_MEMORY((address), (size)) /* ---------------------------------------------------------------- TSan sources say: Annotations useful when defining FIFO queues that transfer data between threads. All unimplemented. Am not claiming to understand this (yet). ---------------------------------------------------------------- */ /* Report that the producer-consumer queue object at address PCQ has been created. The ANNOTATE_PCQ_* annotations should be used only for FIFO queues. For non-FIFO queues use ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */ #define ANNOTATE_PCQ_CREATE(pcq) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_CREATE") /* Report that the queue at address PCQ is about to be destroyed. */ #define ANNOTATE_PCQ_DESTROY(pcq) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_DESTROY") /* Report that we are about to put an element into a FIFO queue at address PCQ. */ #define ANNOTATE_PCQ_PUT(pcq) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_PUT") /* Report that we've just got an element from a FIFO queue at address PCQ. */ #define ANNOTATE_PCQ_GET(pcq) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_GET") /* ---------------------------------------------------------------- Annotations that suppress errors. It is usually better to express the program's synchronization using the other annotations, but these can be used when all else fails. Currently these are all unimplemented. I can't think of a simple way to implement them without at least some performance overhead. ---------------------------------------------------------------- */ /* Report that we may have a benign race at "pointer", with size "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the point where "pointer" has been allocated, preferably close to the point where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. XXX: what's this actually supposed to do? And what's the type of DESCRIPTION? When does the annotation stop having an effect? */ #define ANNOTATE_BENIGN_RACE(pointer, description) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_BENIGN_RACE") /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to the memory range [address, address+size). */ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ VALGRIND_HG_DISABLE_CHECKING(address, size) /* Request the analysis tool to ignore all reads in the current thread until ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey reads, while still checking other reads and all writes. */ #define ANNOTATE_IGNORE_READS_BEGIN() \ _HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_READS_BEGIN") /* Stop ignoring reads. */ #define ANNOTATE_IGNORE_READS_END() \ _HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_READS_END") /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ #define ANNOTATE_IGNORE_WRITES_BEGIN() \ _HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_WRITES_BEGIN") /* Stop ignoring writes. */ #define ANNOTATE_IGNORE_WRITES_END() \ _HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_WRITES_END") /* Start ignoring all memory accesses (reads and writes). */ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ do { \ ANNOTATE_IGNORE_READS_BEGIN(); \ ANNOTATE_IGNORE_WRITES_BEGIN(); \ } while (0) /* Stop ignoring all memory accesses. */ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ do { \ ANNOTATE_IGNORE_WRITES_END(); \ ANNOTATE_IGNORE_READS_END(); \ } while (0) /* ---------------------------------------------------------------- Annotations useful for debugging. Again, so for unimplemented, partly for performance reasons. ---------------------------------------------------------------- */ /* Request to trace every access to ADDRESS. */ #define ANNOTATE_TRACE_MEMORY(address) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_TRACE_MEMORY") /* Report the current thread name to a race detector. */ #define ANNOTATE_THREAD_NAME(name) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_THREAD_NAME") /* ---------------------------------------------------------------- Annotations for describing behaviour of user-implemented lock primitives. In all cases, the LOCK argument is a completely arbitrary machine word (unsigned long, or void*) and can be any value which gives a unique identity to the lock objects being modelled. We just pretend they're ordinary posix rwlocks. That'll probably give some rather confusing wording in error messages, claiming that the arbitrary LOCK values are pthread_rwlock_t*'s, when in fact they are not. Ah well. ---------------------------------------------------------------- */ /* Report that a lock has just been created at address LOCK. */ #define ANNOTATE_RWLOCK_CREATE(lock) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, \ void*,(lock)) /* Report that the lock at address LOCK is about to be destroyed. */ #define ANNOTATE_RWLOCK_DESTROY(lock) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, \ void*,(lock)) /* Report that the lock at address LOCK has just been acquired. is_w=1 for writer lock, is_w=0 for reader lock. */ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED, \ void*,(lock), unsigned long,(is_w)) /* Report that the lock at address LOCK is about to be released. */ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED, \ void*,(lock)) /* is_w is ignored */ /* ------------------------------------------------------------- Annotations useful when implementing barriers. They are not normally needed by modules that merely use barriers. The "barrier" argument is a pointer to the barrier object. ---------------------------------------------------------------- */ /* Report that the "barrier" has been initialized with initial "count". If 'reinitialization_allowed' is true, initialization is allowed to happen multiple times w/o calling barrier_destroy() */ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_INIT") /* Report that we are about to enter barrier_wait("barrier"). */ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_DESTROY") /* Report that we just exited barrier_wait("barrier"). */ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_DESTROY") /* Report that the "barrier" has been destroyed. */ #define ANNOTATE_BARRIER_DESTROY(barrier) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_DESTROY") /* ---------------------------------------------------------------- Annotations useful for testing race detectors. ---------------------------------------------------------------- */ /* Report that we expect a race on the variable at ADDRESS. Use only in unit tests for a race detector. */ #define ANNOTATE_EXPECT_RACE(address, description) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_EXPECT_RACE") /* A no-op. Insert where you like to test the interceptors. */ #define ANNOTATE_NO_OP(arg) \ _HG_CLIENTREQ_UNIMP("ANNOTATE_NO_OP") /* Force the race detector to flush its state. The actual effect depends on * the implementation of the detector. */ #define ANNOTATE_FLUSH_STATE() \ _HG_CLIENTREQ_UNIMP("ANNOTATE_FLUSH_STATE") #endif /* __HELGRIND_H */ pmdk-1.4.1/src/common/valgrind/memcheck.h000066400000000000000000000364051331545616200203000ustar00rootroot00000000000000 /* ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (memcheck.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of MemCheck, a heavyweight Valgrind tool for detecting memory errors. Copyright (C) 2000-2015 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (memcheck.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ #ifndef __MEMCHECK_H #define __MEMCHECK_H /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query memory permissions inside your own programs. See comment near the top of valgrind.h on how to use them. */ #include "valgrind.h" /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), VG_USERREQ__MAKE_MEM_UNDEFINED, VG_USERREQ__MAKE_MEM_DEFINED, VG_USERREQ__DISCARD, VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, VG_USERREQ__CHECK_MEM_IS_DEFINED, VG_USERREQ__DO_LEAK_CHECK, VG_USERREQ__COUNT_LEAKS, VG_USERREQ__GET_VBITS, VG_USERREQ__SET_VBITS, VG_USERREQ__CREATE_BLOCK, VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */ VG_USERREQ__COUNT_LEAK_BLOCKS, VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, VG_USERREQ__CHECK_MEM_IS_UNADDRESSABLE, VG_USERREQ__CHECK_MEM_IS_UNDEFINED, /* This is just for memcheck's internal use - don't use it */ _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR = VG_USERREQ_TOOL_BASE('M','C') + 256 } Vg_MemCheckClientRequest; /* Client-code macros to manipulate the state of memory. */ /* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_NOACCESS, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Similarly, mark memory at _qzz_addr as addressable but undefined for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_UNDEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Similarly, mark memory at _qzz_addr as addressable and defined for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_DEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is not altered: bytes which are addressable are marked as defined, but those which are not addressable are left unchanged. */ #define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Create a block-description handle. The description is an ascii string which is included in any messages pertaining to addresses within the specified memory range. Has no other effect on the properties of the memory range. */ #define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CREATE_BLOCK, \ (_qzz_addr), (_qzz_len), (_qzz_desc), \ 0, 0) /* Discard a block-description-handle. Returns 1 for an invalid handle, 0 for a valid handle. */ #define VALGRIND_DISCARD(_qzz_blkindex) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__DISCARD, \ 0, (_qzz_blkindex), 0, 0, 0) /* Client-code macros to check the state of memory. */ /* Check that memory at _qzz_addr is addressable for _qzz_len bytes. If suitable addressibility is not established, Valgrind prints an error message and returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Check that memory at _qzz_addr is addressable and defined for _qzz_len bytes. If suitable addressibility and definedness are not established, Valgrind prints an error message and returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__CHECK_MEM_IS_DEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Use this macro to force the definedness and addressibility of an lvalue to be checked. If suitable addressibility and definedness are not established, Valgrind prints an error message and returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \ VALGRIND_CHECK_MEM_IS_DEFINED( \ (volatile unsigned char *)&(__lvalue), \ (unsigned long)(sizeof (__lvalue))) /* Check that memory at _qzz_addr is unaddressable for _qzz_len bytes. If any byte in this range is addressable, Valgrind returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_MEM_IS_UNADDRESSABLE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__CHECK_MEM_IS_UNADDRESSABLE,\ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Check that memory at _qzz_addr is undefined for _qzz_len bytes. If any byte in this range is defined or unaddressable, Valgrind returns the address of the first offending byte. Otherwise it returns zero. */ #define VALGRIND_CHECK_MEM_IS_UNDEFINED(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__CHECK_MEM_IS_UNDEFINED, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /* Do a full memory leak check (like --leak-check=full) mid-execution. */ #define VALGRIND_DO_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 0, 0, 0, 0, 0) /* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for which there was an increase in leaked bytes or leaked nr of blocks since the previous leak search. */ #define VALGRIND_DO_ADDED_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 0, 1, 0, 0, 0) /* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with increased or decreased leaked bytes/blocks since previous leak search. */ #define VALGRIND_DO_CHANGED_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 0, 2, 0, 0, 0) /* Do a summary memory leak check (like --leak-check=summary) mid-execution. */ #define VALGRIND_DO_QUICK_LEAK_CHECK \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ 1, 0, 0, 0, 0) /* Return number of leaked, dubious, reachable and suppressed bytes found by all previous leak checks. They must be lvalues. */ #define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \ /* For safety on 64-bit platforms we assign the results to private unsigned long variables, then assign these to the lvalues the user specified, which works no matter what type 'leaked', 'dubious', etc are. We also initialise '_qzz_leaked', etc because VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as defined. */ \ { \ unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ VG_USERREQ__COUNT_LEAKS, \ &_qzz_leaked, &_qzz_dubious, \ &_qzz_reachable, &_qzz_suppressed, 0); \ leaked = _qzz_leaked; \ dubious = _qzz_dubious; \ reachable = _qzz_reachable; \ suppressed = _qzz_suppressed; \ } /* Return number of leaked, dubious, reachable and suppressed bytes found by all previous leak checks. They must be lvalues. */ #define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \ /* For safety on 64-bit platforms we assign the results to private unsigned long variables, then assign these to the lvalues the user specified, which works no matter what type 'leaked', 'dubious', etc are. We also initialise '_qzz_leaked', etc because VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as defined. */ \ { \ unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ VALGRIND_DO_CLIENT_REQUEST_STMT( \ VG_USERREQ__COUNT_LEAK_BLOCKS, \ &_qzz_leaked, &_qzz_dubious, \ &_qzz_reachable, &_qzz_suppressed, 0); \ leaked = _qzz_leaked; \ dubious = _qzz_dubious; \ reachable = _qzz_reachable; \ suppressed = _qzz_suppressed; \ } /* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it into the provided zzvbits array. Return values: 0 if not running on valgrind 1 success 2 [previously indicated unaligned arrays; these are now allowed] 3 if any parts of zzsrc/zzvbits are not addressable. The metadata is not copied in cases 0, 2 or 3 so it should be impossible to segfault your system by using this call. */ #define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__GET_VBITS, \ (const char*)(zza), \ (char*)(zzvbits), \ (zznbytes), 0, 0) /* Set the validity data for addresses [zza..zza+zznbytes-1], copying it from the provided zzvbits array. Return values: 0 if not running on valgrind 1 success 2 [previously indicated unaligned arrays; these are now allowed] 3 if any parts of zza/zzvbits are not addressable. The metadata is not copied in cases 0, 2 or 3 so it should be impossible to segfault your system by using this call. */ #define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__SET_VBITS, \ (const char*)(zza), \ (const char*)(zzvbits), \ (zznbytes), 0, 0 ) /* Disable and re-enable reporting of addressing errors in the specified address range. */ #define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) #define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, \ (_qzz_addr), (_qzz_len), 0, 0, 0) #endif pmdk-1.4.1/src/common/valgrind/pmemcheck.h000066400000000000000000000303421331545616200204520ustar00rootroot00000000000000/* * Copyright (c) 2014-2015, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __PMEMCHECK_H #define __PMEMCHECK_H /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query memory permissions inside your own programs. See comment near the top of valgrind.h on how to use them. */ #include "valgrind.h" /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__PMC_REGISTER_PMEM_MAPPING = VG_USERREQ_TOOL_BASE('P','C'), VG_USERREQ__PMC_REGISTER_PMEM_FILE, VG_USERREQ__PMC_REMOVE_PMEM_MAPPING, VG_USERREQ__PMC_CHECK_IS_PMEM_MAPPING, VG_USERREQ__PMC_PRINT_PMEM_MAPPINGS, VG_USERREQ__PMC_DO_FLUSH, VG_USERREQ__PMC_DO_FENCE, VG_USERREQ__PMC_DO_COMMIT, VG_USERREQ__PMC_WRITE_STATS, VG_USERREQ__PMC_LOG_STORES, VG_USERREQ__PMC_NO_LOG_STORES, VG_USERREQ__PMC_ADD_LOG_REGION, VG_USERREQ__PMC_REMOVE_LOG_REGION, VG_USERREQ__PMC_FULL_REORDED, VG_USERREQ__PMC_PARTIAL_REORDER, VG_USERREQ__PMC_ONLY_FAULT, VG_USERREQ__PMC_STOP_REORDER_FAULT, VG_USERREQ__PMC_SET_CLEAN, /* transaction support */ VG_USERREQ__PMC_START_TX, VG_USERREQ__PMC_START_TX_N, VG_USERREQ__PMC_END_TX, VG_USERREQ__PMC_END_TX_N, VG_USERREQ__PMC_ADD_TO_TX, VG_USERREQ__PMC_ADD_TO_TX_N, VG_USERREQ__PMC_REMOVE_FROM_TX, VG_USERREQ__PMC_REMOVE_FROM_TX_N, VG_USERREQ__PMC_ADD_THREAD_TO_TX_N, VG_USERREQ__PMC_REMOVE_THREAD_FROM_TX_N, VG_USERREQ__PMC_ADD_TO_GLOBAL_TX_IGNORE } Vg_PMemCheckClientRequest; /* Client-code macros to manipulate pmem mappings */ /** Register a persistent memory mapping region */ #define VALGRIND_PMC_REGISTER_PMEM_MAPPING(_qzz_addr, _qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REGISTER_PMEM_MAPPING, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Register a persistent memory file */ #define VALGRIND_PMC_REGISTER_PMEM_FILE(_qzz_desc, _qzz_addr_base, \ _qzz_size, _qzz_offset) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REGISTER_PMEM_FILE, \ (_qzz_desc), (_qzz_addr_base), (_qzz_size), \ (_qzz_offset), 0) /** Remove a persistent memory mapping region */ #define VALGRIND_PMC_REMOVE_PMEM_MAPPING(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REMOVE_PMEM_MAPPING, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Check if the given range is a registered persistent memory mapping */ #define VALGRIND_PMC_CHECK_IS_PMEM_MAPPING(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_CHECK_IS_PMEM_MAPPING, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Register an SFENCE */ #define VALGRIND_PMC_PRINT_PMEM_MAPPINGS \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_PRINT_PMEM_MAPPINGS, \ 0, 0, 0, 0, 0) /** Register a CLFLUSH-like operation */ #define VALGRIND_PMC_DO_FLUSH(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_DO_FLUSH, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Register an SFENCE */ #define VALGRIND_PMC_DO_FENCE \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_DO_FENCE, \ 0, 0, 0, 0, 0) /** Register a PCOMMIT */ #define VALGRIND_PMC_DO_COMMIT \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_DO_COMMIT, \ 0, 0, 0, 0, 0) /** Write tool stats */ #define VALGRIND_PMC_WRITE_STATS \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_WRITE_STATS, \ 0, 0, 0, 0, 0) /** Start logging memory operations */ #define VALGRIND_PMC_LOG_STORES \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_LOG_STORES, \ 0, 0, 0, 0, 0) /** Stop logging memory operations */ #define VALGRIND_PMC_NO_LOG_STORES \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_NO_LOG_STORES, \ 0, 0, 0, 0, 0) /** Add a region of persistent memory, for which all operations will be * logged */ #define VALGRIND_PMC_ADD_LOG_REGION(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_ADD_LOG_REGION, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Remove the loggable persistent memory region */ #define VALGRIND_PMC_REMOVE_LOG_REGION(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REMOVE_LOG_REGION, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Issue a full reorder log */ #define VALGRIND_PMC_FULL_REORDER \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_FULL_REORDED, \ 0, 0, 0, 0, 0) /** Issue a partial reorder log */ #define VALGRIND_PMC_PARTIAL_REORDER \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_PARTIAL_REORDER, \ 0, 0, 0, 0, 0) /** Issue a log to disable reordering */ #define VALGRIND_PMC_ONLY_FAULT \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_ONLY_FAULT, \ 0, 0, 0, 0, 0) /** Issue a log to disable reordering and faults */ #define VALGRIND_PMC_STOP_REORDER_FAULT \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_STOP_REORDER_FAULT, \ 0, 0, 0, 0, 0) /** Set a region of persistent memory as clean */ #define VALGRIND_PMC_SET_CLEAN(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_SET_CLEAN, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Support for transactions */ /** Start an implicit persistent memory transaction */ #define VALGRIND_PMC_START_TX \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_START_TX, \ 0, 0, 0, 0, 0) /** Start an explicit persistent memory transaction */ #define VALGRIND_PMC_START_TX_N(_qzz_txn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_START_TX_N, \ (_qzz_txn), 0, 0, 0, 0) /** End an implicit persistent memory transaction */ #define VALGRIND_PMC_END_TX \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_END_TX, \ 0, 0, 0, 0, 0) /** End an explicit persistent memory transaction */ #define VALGRIND_PMC_END_TX_N(_qzz_txn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_END_TX_N, \ (_qzz_txn), 0, 0, 0, 0) /** Add a persistent memory region to the implicit transaction */ #define VALGRIND_PMC_ADD_TO_TX(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_ADD_TO_TX, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Add a persistent memory region to an explicit transaction */ #define VALGRIND_PMC_ADD_TO_TX_N(_qzz_txn,_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_ADD_TO_TX_N, \ (_qzz_txn), (_qzz_addr), (_qzz_len), 0, 0) /** Remove a persistent memory region from the implicit transaction */ #define VALGRIND_PMC_REMOVE_FROM_TX(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REMOVE_FROM_TX, \ (_qzz_addr), (_qzz_len), 0, 0, 0) /** Remove a persistent memory region from an explicit transaction */ #define VALGRIND_PMC_REMOVE_FROM_TX_N(_qzz_txn,_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REMOVE_FROM_TX_N, \ (_qzz_txn), (_qzz_addr), (_qzz_len), 0, 0) /** End an explicit persistent memory transaction */ #define VALGRIND_PMC_ADD_THREAD_TX_N(_qzz_txn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_ADD_THREAD_TO_TX_N, \ (_qzz_txn), 0, 0, 0, 0) /** End an explicit persistent memory transaction */ #define VALGRIND_PMC_REMOVE_THREAD_FROM_TX_N(_qzz_txn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__PMC_REMOVE_THREAD_FROM_TX_N, \ (_qzz_txn), 0, 0, 0, 0) /** Remove a persistent memory region from the implicit transaction */ #define VALGRIND_PMC_ADD_TO_GLOBAL_TX_IGNORE(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PMC_ADD_TO_GLOBAL_TX_IGNORE,\ (_qzz_addr), (_qzz_len), 0, 0, 0) #endif pmdk-1.4.1/src/common/valgrind/valgrind.h000066400000000000000000014711371331545616200203400ustar00rootroot00000000000000/* -*- c -*- ---------------------------------------------------------------- Notice that the following BSD-style license applies to this one file (valgrind.h) only. The rest of Valgrind is licensed under the terms of the GNU General Public License, version 2, unless otherwise indicated. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- This file is part of Valgrind, a dynamic binary instrumentation framework. Copyright (C) 2000-2015 Julian Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------- Notice that the above BSD-style license applies to this one file (valgrind.h) only. The entire rest of Valgrind is licensed under the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a little bit more slowly than they otherwise would, but otherwise unchanged. When not running on valgrind, each client request consumes very few (eg. 7) instructions, so the resulting performance loss is negligible unless you plan to execute client requests millions of times per second. Nevertheless, if that is still a problem, you can compile with the NVALGRIND symbol defined (gcc -DNVALGRIND) so that client requests are not even compiled in. */ #ifndef __VALGRIND_H #define __VALGRIND_H /* ------------------------------------------------------------------ */ /* VERSION NUMBER OF VALGRIND */ /* ------------------------------------------------------------------ */ /* Specify Valgrind's version number, so that user code can conditionally compile based on our version number. Note that these were introduced at version 3.6 and so do not exist in version 3.5 or earlier. The recommended way to use them to check for "version X.Y or later" is (eg) #if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ && (__VALGRIND_MAJOR__ > 3 \ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) */ #define __VALGRIND_MAJOR__ 3 #define __VALGRIND_MINOR__ 12 #include /* Nb: this file might be included in a file compiled with -ansi. So we can't use C++ style "//" comments nor the "asm" keyword (instead use "__asm__"). */ /* Derive some tags indicating what the target platform is. Note that in this file we're using the compiler's CPP symbols for identifying architectures, which are different to the ones we use within the rest of Valgrind. Note, __powerpc__ is active for both 32 and 64-bit PPC, whereas __powerpc64__ is only active for the latter (on Linux, that is). Misc note: how to find out what's predefined in gcc by default: gcc -Wp,-dM somefile.c */ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_arm64_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_tilegx_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #if defined(__APPLE__) && defined(__i386__) # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 #elif (defined(__MINGW32__) && !defined(__MINGW64__)) \ || defined(__CYGWIN32__) \ || (defined(_WIN32) && defined(_M_IX86)) # define PLAT_x86_win32 1 #elif defined(__MINGW64__) \ || (defined(_WIN64) && defined(_M_X64)) # define PLAT_amd64_win64 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) # define PLAT_amd64_linux 1 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) # define PLAT_ppc32_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 /* Big Endian uses ELF version 1 */ # define PLAT_ppc64be_linux 1 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 /* Little Endian uses ELF version 2 */ # define PLAT_ppc64le_linux 1 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) # define PLAT_arm_linux 1 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) # define PLAT_arm64_linux 1 #elif defined(__linux__) && defined(__s390__) && defined(__s390x__) # define PLAT_s390x_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips==64) # define PLAT_mips64_linux 1 #elif defined(__linux__) && defined(__mips__) && (__mips!=64) # define PLAT_mips32_linux 1 #elif defined(__linux__) && defined(__tilegx__) # define PLAT_tilegx_linux 1 #elif defined(__sun) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun) && defined(__x86_64__) # define PLAT_amd64_solaris 1 #else /* If we're not compiling for our target platform, don't generate any inline asms. */ # if !defined(NVALGRIND) # define NVALGRIND 1 # endif #endif /* ------------------------------------------------------------------ */ /* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ /* in here of use to end-users -- skip to the next section. */ /* ------------------------------------------------------------------ */ /* * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client * request. Accepts both pointers and integers as arguments. * * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind * client request that does not return a value. * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind * client request and whose value equals the client request result. Accepts * both pointers and integers as arguments. Note that such calls are not * necessarily pure functions -- they may have side effects. */ #define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ _zzq_request, _zzq_arg1, _zzq_arg2, \ _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) #if defined(NVALGRIND) /* Define NVALGRIND to completely remove the Valgrind magic sequence from the compiled code (analogous to NDEBUG's effects on assert()) */ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ (_zzq_default) #else /* ! NVALGRIND */ /* The following defines the magic code sequences which the JITter spots and handles magically. Don't look too closely at them as they will rot your brain. The assembly code sequences for all architectures is in this one file. This is because this file must be stand-alone, and we don't want to have multiple files. For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default value gets put in the return slot, so that everything works when this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code _zzq_arg1..5 request params The other two macros are used to support function wrapping, and are a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the guest's NRADDR pseudo-register and whatever other information is needed to safely run the call original from the wrapper: on ppc64-linux, the R2 value at the divert point is also needed. This information is abstracted into a user-visible type, OrigFn. VALGRIND_CALL_NOREDIR_* behaves the same as the following on the guest, but guarantees that the branch instruction will not be redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a complete inline asm, since it needs to be combined with more magic inline asm stuff to be useful. */ /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ || defined(PLAT_x86_solaris) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "roll $3, %%edi ; roll $13, %%edi\n\t" \ "roll $29, %%edi ; roll $19, %%edi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EDX = client_request ( %EAX ) */ \ "xchgl %%ebx,%%ebx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ "xchgl %%ecx,%%ecx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%EAX */ \ "xchgl %%edx,%%edx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgl %%edi,%%edi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) || PLAT_x86_solaris */ /* ------------------------- x86-Win32 ------------------------- */ #if defined(PLAT_x86_win32) && !defined(__GNUC__) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #if defined(_MSC_VER) #define __SPECIAL_INSTRUCTION_PREAMBLE \ __asm rol edi, 3 __asm rol edi, 13 \ __asm rol edi, 29 __asm rol edi, 19 #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) static __inline uintptr_t valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, uintptr_t _zzq_arg5) { volatile uintptr_t _zzq_args[6]; volatile unsigned int _zzq_result; _zzq_args[0] = (uintptr_t)(_zzq_request); _zzq_args[1] = (uintptr_t)(_zzq_arg1); _zzq_args[2] = (uintptr_t)(_zzq_arg2); _zzq_args[3] = (uintptr_t)(_zzq_arg3); _zzq_args[4] = (uintptr_t)(_zzq_arg4); _zzq_args[5] = (uintptr_t)(_zzq_arg5); __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default __SPECIAL_INSTRUCTION_PREAMBLE /* %EDX = client_request ( %EAX ) */ __asm xchg ebx,ebx __asm mov _zzq_result, edx } return _zzq_result; } #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ /* %EAX = guest_NRADDR */ \ __asm xchg ecx,ecx \ __asm mov __addr, eax \ } \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_EAX ERROR #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ __asm xchg edi,edi \ } \ } while (0) #else #error Unsupported compiler. #endif #endif /* PLAT_x86_win32 */ /* ----------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) \ || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RDX = client_request ( %RAX ) */ \ "xchgq %%rbx,%%rbx" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RAX = guest_NRADDR */ \ "xchgq %%rcx,%%rcx" \ : "=a" (__addr) \ : \ : "cc", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_RAX \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%RAX */ \ "xchgq %%rdx,%%rdx\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "xchgq %%rdi,%%rdi\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------- amd64-Win64 ------------------------- */ #if defined(PLAT_amd64_win64) && !defined(__GNUC__) #error Unsupported compiler. #endif /* PLAT_amd64_win64 */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned int _zzq_args[6]; \ unsigned int _zzq_result; \ unsigned int* _zzq_ptr; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R11 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64be_linux */ #if defined(PLAT_ppc64le_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ unsigned long int r2; /* what tocptr do we need? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,61 ; rotldi 0,0,51\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({ unsigned long int _zzq_args[6]; \ unsigned long int _zzq_result; \ unsigned long int* _zzq_ptr; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ _zzq_ptr = _zzq_args; \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \ "mr 4,%2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = client_request ( %R4 ) */ \ "or 1,1,1\n\t" \ "mr %0,3" /*result*/ \ : "=b" (_zzq_result) \ : "b" (_zzq_default), "b" (_zzq_ptr) \ : "cc", "memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR */ \ "or 2,2,2\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %R3 = guest_NRADDR_GPR2 */ \ "or 4,4,4\n\t" \ "mr %0,3" \ : "=b" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->r2 = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R12 */ \ "or 3,3,3\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or 5,5,5\n\t" \ ); \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("mov r3, %1\n\t" /*default*/ \ "mov r4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = client_request ( R4 ) */ \ "orr r10, r10, r10\n\t" \ "mov %0, r3" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "cc","memory", "r3", "r4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* R3 = guest_NRADDR */ \ "orr r11, r11, r11\n\t" \ "mov %0, r3" \ : "=r" (__addr) \ : \ : "cc", "memory", "r3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir *%R4 */ \ "orr r12, r12, r12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr r9, r9, r9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------- */ #if defined(PLAT_arm64_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; #define __SPECIAL_INSTRUCTION_PREAMBLE \ "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("mov x3, %1\n\t" /*default*/ \ "mov x4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = client_request ( X4 ) */ \ "orr x10, x10, x10\n\t" \ "mov %0, x3" /*result*/ \ : "=r" (_zzq_result) \ : "r" ((unsigned long int)(_zzq_default)), \ "r" (&_zzq_args[0]) \ : "cc","memory", "x3", "x4"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* X3 = guest_NRADDR */ \ "orr x11, x11, x11\n\t" \ "mov %0, x3" \ : "=r" (__addr) \ : \ : "cc", "memory", "x3" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* branch-and-link-to-noredir X8 */ \ "orr x12, x12, x12\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "orr x9, x9, x9\n\t" \ : : : "cc", "memory" \ ); \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------ s390x-linux ------------------------ */ #if defined(PLAT_s390x_linux) typedef struct { unsigned long int nraddr; /* where's the code? */ } OrigFn; /* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific * code. This detection is implemented in platform specific toIR.c * (e.g. VEX/priv/guest_s390_decoder.c). */ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "lr 15,15\n\t" \ "lr 1,1\n\t" \ "lr 2,2\n\t" \ "lr 3,3\n\t" #define __CLIENT_REQUEST_CODE "lr 2,2\n\t" #define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" #define __CALL_NO_REDIR_CODE "lr 4,4\n\t" #define __VEX_INJECT_IR_CODE "lr 5,5\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile(/* r2 = args */ \ "lgr 2,%1\n\t" \ /* r3 = default */ \ "lgr 3,%2\n\t" \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CLIENT_REQUEST_CODE \ /* results = r3 */ \ "lgr %0, 3\n\t" \ : "=d" (_zzq_result) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "cc", "2", "3", "memory" \ ); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __GET_NR_CONTEXT_CODE \ "lgr %0, 3\n\t" \ : "=a" (__addr) \ : \ : "cc", "3", "memory" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_R1 \ __SPECIAL_INSTRUCTION_PREAMBLE \ __CALL_NO_REDIR_CODE #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __VEX_INJECT_IR_CODE); \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ---------------- */ #if defined(PLAT_mips32_linux) typedef struct { unsigned int nraddr; /* where's the code? */ } OrigFn; /* .word 0x342 * .word 0x742 * .word 0xC2 * .word 0x4C2*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "srl $0, $0, 13\n\t" \ "srl $0, $0, 29\n\t" \ "srl $0, $0, 3\n\t" \ "srl $0, $0, 19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned int _zzq_args[6]; \ volatile unsigned int _zzq_result; \ _zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* T3 = client_request ( T4 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %t9 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir *%t9 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- mips64-linux ---------------- */ #if defined(PLAT_mips64_linux) typedef struct { unsigned long nraddr; /* where's the code? */ } OrigFn; /* dsll $0,$0, 3 * dsll $0,$0, 13 * dsll $0,$0, 29 * dsll $0,$0, 19*/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ "dsll $0,$0,29 ; dsll $0,$0,19\n\t" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ ({ volatile unsigned long int _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ _zzq_args[0] = (unsigned long int)(_zzq_request); \ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = client_request ( $12 ) */ \ "or $13, $13, $13\n\t" \ "move %0, $11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "$11", "$12", "memory"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* $11 = guest_NRADDR */ \ "or $14, $14, $14\n\t" \ "move %0, $11" /*result*/ \ : "=r" (__addr) \ : \ : "$11"); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_T9 \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* call-noredir $25 */ \ "or $15, $15, $15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or $11, $11, $11\n\t" \ ); \ } while (0) #endif /* PLAT_mips64_linux */ /* ------------------------ tilegx-linux --------------- */ #if defined(PLAT_tilegx_linux) typedef struct { unsigned long long int nraddr; /* where's the code? */ } OrigFn; /*** special instruction sequence. 0:02b3c7ff91234fff { moveli zero, 4660 ; moveli zero, 22136 } 8:0091a7ff95678fff { moveli zero, 22136 ; moveli zero, 4660 } ****/ #define __SPECIAL_INSTRUCTION_PREAMBLE \ ".quad 0x02b3c7ff91234fff\n" \ ".quad 0x0091a7ff95678fff\n" #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ ({ volatile unsigned long long int _zzq_args[6]; \ volatile unsigned long long int _zzq_result; \ _zzq_args[0] = (unsigned long long int)(_zzq_request); \ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ __asm__ volatile("move r11, %1\n\t" /*default*/ \ "move r12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ /* r11 = client_request */ \ "or r13, r13, r13\n\t" \ "move %0, r11\n\t" /*result*/ \ : "=r" (_zzq_result) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \ : "memory", "r11", "r12"); \ _zzq_result; \ }) #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ volatile unsigned long long int __addr; \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* r11 = guest_NRADDR */ \ "or r14, r14, r14\n" \ "move %0, r11\n" \ : "=r" (__addr) \ : \ : "memory", "r11" \ ); \ _zzq_orig->nraddr = __addr; \ } #define VALGRIND_CALL_NOREDIR_R12 \ __SPECIAL_INSTRUCTION_PREAMBLE \ "or r15, r15, r15\n\t" #define VALGRIND_VEX_INJECT_IR() \ do { \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ "or r11, r11, r11\n\t" \ ); \ } while (0) #endif /* PLAT_tilegx_linux */ /* Insert assembly code for other platforms here... */ #endif /* NVALGRIND */ /* ------------------------------------------------------------------ */ /* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ /* ugly. It's the least-worst tradeoff I can think of. */ /* ------------------------------------------------------------------ */ /* This section defines magic (a.k.a appalling-hack) macros for doing guaranteed-no-redirection macros, so as to get from function wrappers to the functions they are wrapping. The whole point is to construct standard call sequences, but to do the call itself with a special no-redirect call pseudo-instruction that the JIT understands and handles specially. This section is long and repetitious, and I can't see a way to make it shorter. The naming scheme is as follows: CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} 'W' stands for "word" and 'v' for "void". Hence there are different macros for calling arity 0, 1, 2, 3, 4, etc, functions, and for each, the possibility of returning a word-typed result, or no result. */ /* Use these to write the name of your wrapper. NOTE: duplicates VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts the default behaviour equivalance class tag "0000" into the name. See pub_tool_redir.h for details -- normally you don't need to think about this, though. */ /* Use an extra level of macroisation so as to ensure the soname/fnname args are fully macro-expanded before pasting them together. */ #define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd #define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) #define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) /* Use this macro from within a wrapper function to collect the context (address and possibly other info) of the original function. Once you have that you can then use it in one of the CALL_FN_ macros. The type of the argument _lval is OrigFn. */ #define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) /* Also provide end-user facilities for function replacement, rather than wrapping. A replacement function differs from a wrapper in that it has no way to get hold of the original function being called, and hence no way to call onwards to it. In a replacement function, VALGRIND_GET_ORIG_FN always returns zero. */ #define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) #define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) /* Derivatives of the main macros below, for calling functions returning void. */ #define CALL_FN_v_v(fnptr) \ do { volatile unsigned long _junk; \ CALL_FN_W_v(_junk,fnptr); } while (0) #define CALL_FN_v_W(fnptr, arg1) \ do { volatile unsigned long _junk; \ CALL_FN_W_W(_junk,fnptr,arg1); } while (0) #define CALL_FN_v_WW(fnptr, arg1,arg2) \ do { volatile unsigned long _junk; \ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) #define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) #define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ do { volatile unsigned long _junk; \ CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) #define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ do { volatile unsigned long _junk; \ CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) #define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ do { volatile unsigned long _junk; \ CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) #define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ do { volatile unsigned long _junk; \ CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || defined(PLAT_x86_solaris) /* These regs are trashed by the hidden call. No need to mention eax as gcc can already see that, plus causes gcc to bomb. */ #define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movl %%esp,%%edi\n\t" \ "andl $0xfffffff0,%%esp\n\t" #define VALGRIND_RESTORE_STACK \ "movl %%edi,%%esp\n\t" /* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $12, %%esp\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $8, %%esp\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "subl $4, %%esp\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "pushl 48(%%eax)\n\t" \ "pushl 44(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \ VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_RESTORE_STACK \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ /* ---------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ "rdi", "r8", "r9", "r10", "r11" /* This is all pretty complex. It's so as to make stack unwinding work reliably. See bug 243270. The basic problem is the sub and add of 128 of %rsp in all of the following macros. If gcc believes the CFA is in %rsp, then unwinding may fail, because what's at the CFA is not what gcc "expected" when it constructs the CFIs for the places where the macros are instantiated. But we can't just add a CFI annotation to increase the CFA offset by 128, to match the sub of 128 from %rsp, because we don't know whether gcc has chosen %rsp as the CFA at that point, or whether it has chosen some other register (eg, %rbp). In the latter case, adding a CFI annotation to change the CFA offset is simply wrong. So the solution is to get hold of the CFA using __builtin_dwarf_cfa(), put it in a known register, and add a CFI annotation to say what the register is. We choose %rbp for this (perhaps perversely), because: (1) %rbp is already subject to unwinding. If a new register was chosen then the unwinder would have to unwind it in all stack traces, which is expensive, and (2) %rbp is already subject to precise exception updates in the JIT. If a new register was chosen, we'd have to have precise exceptions for it too, which reduces performance of the generated code. However .. one extra complication. We can't just whack the result of __builtin_dwarf_cfa() into %rbp and then add %rbp to the list of trashed registers at the end of the inline assembly fragments; gcc won't allow %rbp to appear in that list. Hence instead we need to stash %rbp in %r15 for the duration of the asm, and say that %r15 is trashed instead. gcc seems happy to go with that. Oh .. and this all needs to be conditionalised so that it is unchanged from before this commit, when compiled with older gccs that don't support __builtin_dwarf_cfa. Furthermore, since this header file is freestanding, it has to be independent of config.h, and so the following conditionalisation cannot depend on configure time checks. Although it's not clear from 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', this expression excludes Darwin. .cfi directives in Darwin assembly appear to be completely different and I haven't investigated how they work. For even more entertainment value, note we have to use the completely undocumented __builtin_dwarf_cfa(), which appears to really compute the CFA, whereas __builtin_frame_address(0) claims to but actually doesn't. See https://bugs.kde.org/show_bug.cgi?id=243270#c47 */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"r"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ "movq %%rbp, %%r15\n\t" \ "movq %2, %%rbp\n\t" \ ".cfi_remember_state\n\t" \ ".cfi_def_cfa rbp, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "movq %%r15, %%rbp\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE # define VALGRIND_CFI_EPILOGUE #endif /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "movq %%rsp,%%r14\n\t" \ "andq $0xfffffffffffffff0,%%rsp\n\t" #define VALGRIND_RESTORE_STACK \ "movq %%r14,%%rsp\n\t" /* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned long) == 8. */ /* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ macros. In order not to trash the stack redzone, we need to drop %rsp by 128 before the hidden call, and restore afterwards. The nastyness is that it is only by luck that the stack still appears to be unwindable during the hidden call - since then the behaviour of any routine using this macro does not match what the CFI data says. Sigh. Why is this important? Imagine that a wrapper has a stack allocated local, and passes to the hidden call, a pointer to it. Because gcc does not know about the hidden call, it may allocate that local in the redzone. Unfortunately the hidden call may then trash it before it comes to use it. So we must step clear of the redzone, for the duration of the hidden call, to make it safe. Probably the same problem afflicts the other redzone-style ABIs too (ppc64-linux); but for those, the stack is self describing (none of this CFI nonsense) so at least messing with the stack pointer doesn't give a danger of non-unwindable stack. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $136,%%rsp\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ VALGRIND_ALIGN_STACK \ "subq $128,%%rsp\n\t" \ "pushq 96(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \ "movq 48(%%rax), %%r9\n\t" \ "movq 40(%%rax), %%r8\n\t" \ "movq 32(%%rax), %%rcx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \ "movq 16(%%rax), %%rsi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \ VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_RESTORE_STACK \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=a" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ /* ------------------------ ppc32-linux ------------------------ */ #if defined(PLAT_ppc32_linux) /* This is useful for finding out about the on-stack stuff: extern int f9 ( int,int,int,int,int,int,int,int,int ); extern int f10 ( int,int,int,int,int,int,int,int,int,int ); extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); int g9 ( void ) { return f9(11,22,33,44,55,66,77,88,99); } int g10 ( void ) { return f10(11,22,33,44,55,66,77,88,99,110); } int g11 ( void ) { return f11(11,22,33,44,55,66,77,88,99,110,121); } int g12 ( void ) { return f12(11,22,33,44,55,66,77,88,99,110,121,132); } */ /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rlwinm 1,1,0,0,27\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc32-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-16\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "addi 1,1,-32\n\t" \ /* arg12 */ \ "lwz 3,48(11)\n\t" \ "stw 3,20(1)\n\t" \ /* arg11 */ \ "lwz 3,44(11)\n\t" \ "stw 3,16(1)\n\t" \ /* arg10 */ \ "lwz 3,40(11)\n\t" \ "stw 3,12(1)\n\t" \ /* arg9 */ \ "lwz 3,36(11)\n\t" \ "stw 3,8(1)\n\t" \ /* args1-8 */ \ "lwz 3,4(11)\n\t" /* arg1->r3 */ \ "lwz 4,8(11)\n\t" \ "lwz 5,12(11)\n\t" \ "lwz 6,16(11)\n\t" /* arg4->r6 */ \ "lwz 7,20(11)\n\t" \ "lwz 8,24(11)\n\t" \ "lwz 9,28(11)\n\t" \ "lwz 10,32(11)\n\t" /* arg8->r10 */ \ "lwz 11,0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ VALGRIND_RESTORE_STACK \ "mr %0,3" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc32_linux */ /* ------------------------ ppc64-linux ------------------------ */ #if defined(PLAT_ppc64be_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 11,%1\n\t" \ "std 2,-16(11)\n\t" /* save tocptr */ \ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(11)\n\t" \ "std 3,136(1)\n\t" \ /* arg11 */ \ "ld 3,88(11)\n\t" \ "std 3,128(1)\n\t" \ /* arg10 */ \ "ld 3,80(11)\n\t" \ "std 3,120(1)\n\t" \ /* arg9 */ \ "ld 3,72(11)\n\t" \ "std 3,112(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ld 9, 56(11)\n\t" /* arg7->r9 */ \ "ld 10, 64(11)\n\t" /* arg8->r10 */ \ "ld 11, 0(11)\n\t" /* target->r11 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ "mr 11,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(11)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64be_linux */ /* ------------------------- ppc64le-linux ----------------------- */ #if defined(PLAT_ppc64le_linux) /* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "lr", "ctr", "xer", \ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ "r11", "r12", "r13" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ #define VALGRIND_ALIGN_STACK \ "mr 28,1\n\t" \ "rldicr 1,1,0,59\n\t" #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" /* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+0]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+1]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+2]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+3]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+4]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+5]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+6]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+7]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+8]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+9]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+10]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-128\n\t" /* expand stack frame */ \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+11]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3+12]; \ volatile unsigned long _res; \ /* _argvec[0] holds current r2 across the call */ \ _argvec[1] = (unsigned long)_orig.r2; \ _argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2+1] = (unsigned long)arg1; \ _argvec[2+2] = (unsigned long)arg2; \ _argvec[2+3] = (unsigned long)arg3; \ _argvec[2+4] = (unsigned long)arg4; \ _argvec[2+5] = (unsigned long)arg5; \ _argvec[2+6] = (unsigned long)arg6; \ _argvec[2+7] = (unsigned long)arg7; \ _argvec[2+8] = (unsigned long)arg8; \ _argvec[2+9] = (unsigned long)arg9; \ _argvec[2+10] = (unsigned long)arg10; \ _argvec[2+11] = (unsigned long)arg11; \ _argvec[2+12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "mr 12,%1\n\t" \ "std 2,-16(12)\n\t" /* save tocptr */ \ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ "addi 1,1,-144\n\t" /* expand stack frame */ \ /* arg12 */ \ "ld 3,96(12)\n\t" \ "std 3,120(1)\n\t" \ /* arg11 */ \ "ld 3,88(12)\n\t" \ "std 3,112(1)\n\t" \ /* arg10 */ \ "ld 3,80(12)\n\t" \ "std 3,104(1)\n\t" \ /* arg9 */ \ "ld 3,72(12)\n\t" \ "std 3,96(1)\n\t" \ /* args1-8 */ \ "ld 3, 8(12)\n\t" /* arg1->r3 */ \ "ld 4, 16(12)\n\t" /* arg2->r4 */ \ "ld 5, 24(12)\n\t" /* arg3->r5 */ \ "ld 6, 32(12)\n\t" /* arg4->r6 */ \ "ld 7, 40(12)\n\t" /* arg5->r7 */ \ "ld 8, 48(12)\n\t" /* arg6->r8 */ \ "ld 9, 56(12)\n\t" /* arg7->r9 */ \ "ld 10, 64(12)\n\t" /* arg8->r10 */ \ "ld 12, 0(12)\n\t" /* target->r12 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ "mr 12,%1\n\t" \ "mr %0,3\n\t" \ "ld 2,-16(12)\n\t" /* restore tocptr */ \ VALGRIND_RESTORE_STACK \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[2]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_ppc64le_linux */ /* ------------------------- arm-linux ------------------------- */ #if defined(PLAT_arm_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" /* Macros to save and align the stack before making a function call and restore it afterwards as gcc may not keep the stack pointer aligned if it doesn't realise calls are being made to other functions. */ /* This is a bit tricky. We store the original stack pointer in r10 as it is callee-saves. gcc doesn't allow the use of r11 for some reason. Also, we can't directly "bic" the stack pointer in thumb mode since r13 isn't an allowed register number in that context. So use r4 as a temporary, since that is about to get trashed anyway, just after each use of this macro. Side effect is we need to be very careful about any future changes, since VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ #define VALGRIND_ALIGN_STACK \ "mov r10, sp\n\t" \ "mov r4, sp\n\t" \ "bic r4, r4, #7\n\t" \ "mov sp, r4\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, r10\n\t" /* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "push {r0, r1, r2, r3} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "push {r0} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #4 \n\t" \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "push {r0, r1} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr r0, [%1, #40] \n\t" \ "ldr r1, [%1, #44] \n\t" \ "ldr r2, [%1, #48] \n\t" \ "push {r0, r1, r2} \n\t" \ "ldr r0, [%1, #20] \n\t" \ "ldr r1, [%1, #24] \n\t" \ "ldr r2, [%1, #28] \n\t" \ "ldr r3, [%1, #32] \n\t" \ "ldr r4, [%1, #36] \n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \ "ldr r0, [%1, #4] \n\t" \ "ldr r1, [%1, #8] \n\t" \ "ldr r2, [%1, #12] \n\t" \ "ldr r3, [%1, #16] \n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ VALGRIND_RESTORE_STACK \ "mov %0, r0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm_linux */ /* ------------------------ arm64-linux ------------------------ */ #if defined(PLAT_arm64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS \ "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ "x18", "x19", "x20", "x30", \ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ "v26", "v27", "v28", "v29", "v30", "v31" /* x21 is callee-saved, so we can use it to save and restore SP around the hidden call. */ #define VALGRIND_ALIGN_STACK \ "mov x21, sp\n\t" \ "bic sp, x21, #15\n\t" #define VALGRIND_RESTORE_STACK \ "mov sp, x21\n\t" /* These CALL_FN_ macros assume that on arm64-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x20 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10,arg11, \ arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ VALGRIND_ALIGN_STACK \ "sub sp, sp, #0x30 \n\t" \ "ldr x0, [%1, #8] \n\t" \ "ldr x1, [%1, #16] \n\t" \ "ldr x2, [%1, #24] \n\t" \ "ldr x3, [%1, #32] \n\t" \ "ldr x4, [%1, #40] \n\t" \ "ldr x5, [%1, #48] \n\t" \ "ldr x6, [%1, #56] \n\t" \ "ldr x7, [%1, #64] \n\t" \ "ldr x8, [%1, #72] \n\t" \ "str x8, [sp, #0] \n\t" \ "ldr x8, [%1, #80] \n\t" \ "str x8, [sp, #8] \n\t" \ "ldr x8, [%1, #88] \n\t" \ "str x8, [sp, #16] \n\t" \ "ldr x8, [%1, #96] \n\t" \ "str x8, [sp, #24] \n\t" \ "ldr x8, [%1] \n\t" /* target->x8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ VALGRIND_RESTORE_STACK \ "mov %0, x0" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_arm64_linux */ /* ------------------------- s390x-linux ------------------------- */ #if defined(PLAT_s390x_linux) /* Similar workaround as amd64 (see above), but we use r11 as frame pointer and save the old r11 in r7. r11 might be used for argvec, therefore we copy argvec in r1 since r1 is clobbered after the call anyway. */ #if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) # define __FRAME_POINTER \ ,"d"(__builtin_dwarf_cfa()) # define VALGRIND_CFI_PROLOGUE \ ".cfi_remember_state\n\t" \ "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ "lgr 7,11\n\t" \ "lgr 11,%2\n\t" \ ".cfi_def_cfa r11, 0\n\t" # define VALGRIND_CFI_EPILOGUE \ "lgr 11, 7\n\t" \ ".cfi_restore_state\n\t" #else # define __FRAME_POINTER # define VALGRIND_CFI_PROLOGUE \ "lgr 1,%1\n\t" # define VALGRIND_CFI_EPILOGUE #endif /* Nb: On s390 the stack pointer is properly aligned *at all times* according to the s390 GCC maintainer. (The ABI specification is not precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and VALGRIND_RESTORE_STACK are not defined here. */ /* These regs are trashed by the hidden call. Note that we overwrite r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the function a proper return address. All others are ABI defined call clobbers. */ #define __CALLER_SAVED_REGS "0","1","2","3","4","5","14", \ "f0","f1","f2","f3","f4","f5","f6","f7" /* Nb: Although r11 is modified in the asm snippets below (inside VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for two reasons: (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not modified (2) GCC will complain that r11 cannot appear inside a clobber section, when compiled with -O -fno-omit-frame-pointer */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 1, 0(1)\n\t" /* target->r1 */ \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) /* The call abi has the arguments in r2-r6 and stack */ #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1, arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-160\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,160\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-168\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,168\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-176\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,176\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-184\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,184\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-192\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,192\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-200\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,200\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-208\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,208\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ _argvec[3] = (unsigned long)arg3; \ _argvec[4] = (unsigned long)arg4; \ _argvec[5] = (unsigned long)arg5; \ _argvec[6] = (unsigned long)arg6; \ _argvec[7] = (unsigned long)arg7; \ _argvec[8] = (unsigned long)arg8; \ _argvec[9] = (unsigned long)arg9; \ _argvec[10] = (unsigned long)arg10; \ _argvec[11] = (unsigned long)arg11; \ _argvec[12] = (unsigned long)arg12; \ __asm__ volatile( \ VALGRIND_CFI_PROLOGUE \ "aghi 15,-216\n\t" \ "lg 2, 8(1)\n\t" \ "lg 3,16(1)\n\t" \ "lg 4,24(1)\n\t" \ "lg 5,32(1)\n\t" \ "lg 6,40(1)\n\t" \ "mvc 160(8,15), 48(1)\n\t" \ "mvc 168(8,15), 56(1)\n\t" \ "mvc 176(8,15), 64(1)\n\t" \ "mvc 184(8,15), 72(1)\n\t" \ "mvc 192(8,15), 80(1)\n\t" \ "mvc 200(8,15), 88(1)\n\t" \ "mvc 208(8,15), 96(1)\n\t" \ "lg 1, 0(1)\n\t" \ VALGRIND_CALL_NOREDIR_R1 \ "lgr %0, 2\n\t" \ "aghi 15,216\n\t" \ VALGRIND_CFI_EPILOGUE \ : /*out*/ "=d" (_res) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ----------------------- */ #if defined(PLAT_mips32_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16\n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" /* arg1*/ \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "subu $29, $29, 16 \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 16 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 24\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 24 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "nop\n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 32\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 32 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 40\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 40 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 48\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 48 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "subu $29, $29, 8 \n\t" \ "sw $28, 0($29) \n\t" \ "sw $31, 4($29) \n\t" \ "lw $4, 20(%1) \n\t" \ "subu $29, $29, 56\n\t" \ "sw $4, 16($29) \n\t" \ "lw $4, 24(%1) \n\t" \ "sw $4, 20($29) \n\t" \ "lw $4, 28(%1) \n\t" \ "sw $4, 24($29) \n\t" \ "lw $4, 32(%1) \n\t" \ "sw $4, 28($29) \n\t" \ "lw $4, 36(%1) \n\t" \ "sw $4, 32($29) \n\t" \ "lw $4, 40(%1) \n\t" \ "sw $4, 36($29) \n\t" \ "lw $4, 44(%1) \n\t" \ "sw $4, 40($29) \n\t" \ "lw $4, 48(%1) \n\t" \ "sw $4, 44($29) \n\t" \ "lw $4, 4(%1) \n\t" \ "lw $5, 8(%1) \n\t" \ "lw $6, 12(%1) \n\t" \ "lw $7, 16(%1) \n\t" \ "lw $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "addu $29, $29, 56 \n\t" \ "lw $28, 0($29) \n\t" \ "lw $31, 4($29) \n\t" \ "addu $29, $29, 8 \n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_mips32_linux */ /* ------------------------- mips64-linux ------------------------- */ #if defined(PLAT_mips64_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ "$25", "$31" /* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "0" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" /* arg1*/ \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1) \n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "dsubu $29, $29, 8\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 8\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "dsubu $29, $29, 16\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 16\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "dsubu $29, $29, 24\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 24\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "dsubu $29, $29, 32\n\t" \ "ld $4, 72(%1)\n\t" \ "sd $4, 0($29)\n\t" \ "ld $4, 80(%1)\n\t" \ "sd $4, 8($29)\n\t" \ "ld $4, 88(%1)\n\t" \ "sd $4, 16($29)\n\t" \ "ld $4, 96(%1)\n\t" \ "sd $4, 24($29)\n\t" \ "ld $4, 8(%1)\n\t" \ "ld $5, 16(%1)\n\t" \ "ld $6, 24(%1)\n\t" \ "ld $7, 32(%1)\n\t" \ "ld $8, 40(%1)\n\t" \ "ld $9, 48(%1)\n\t" \ "ld $10, 56(%1)\n\t" \ "ld $11, 64(%1)\n\t" \ "ld $25, 0(%1)\n\t" /* target->t9 */ \ VALGRIND_CALL_NOREDIR_T9 \ "daddu $29, $29, 32\n\t" \ "move %0, $2\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS \ ); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_mips64_linux */ /* ------------------------ tilegx-linux ------------------------- */ #if defined(PLAT_tilegx_linux) /* These regs are trashed by the hidden call. */ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3", "r4", "r5", \ "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", \ "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", \ "r23", "r24", "r25", "r26", "r27", "r28", "r29", "lr" /* These CALL_FN_ macros assume that on tilegx-linux, sizeof(unsigned long) == 8. */ #define CALL_FN_W_v(lval, orig) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[1]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "ld r12, %1 \n\t" /* target->r11 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0 \n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[2]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WW(lval, orig, arg1,arg2) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[3]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[4]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8 \n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[5]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[6]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[7]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[8]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[9]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[10]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ arg7,arg8,arg9,arg10) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[11]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */ \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 8\n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[12]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */ \ "ld r10, r29 \n\t" \ "st_add sp, r10, -16 \n\t" \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 24 \n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ arg6,arg7,arg8,arg9,arg10, \ arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ volatile unsigned long _argvec[13]; \ volatile unsigned long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ _argvec[3] = (unsigned long)(arg3); \ _argvec[4] = (unsigned long)(arg4); \ _argvec[5] = (unsigned long)(arg5); \ _argvec[6] = (unsigned long)(arg6); \ _argvec[7] = (unsigned long)(arg7); \ _argvec[8] = (unsigned long)(arg8); \ _argvec[9] = (unsigned long)(arg9); \ _argvec[10] = (unsigned long)(arg10); \ _argvec[11] = (unsigned long)(arg11); \ _argvec[12] = (unsigned long)(arg12); \ __asm__ volatile( \ "addi sp, sp, -8 \n\t" \ "st_add sp, lr, -8 \n\t" \ "move r29, %1 \n\t" \ "ld_add r12, r29, 8 \n\t" /* target->r11 */ \ "ld_add r0, r29, 8 \n\t" /*arg1 -> r0 */ \ "ld_add r1, r29, 8 \n\t" /*arg2 -> r1 */ \ "ld_add r2, r29, 8 \n\t" /*arg3 -> r2 */ \ "ld_add r3, r29, 8 \n\t" /*arg4 -> r3 */ \ "ld_add r4, r29, 8 \n\t" /*arg5 -> r4 */ \ "ld_add r5, r29, 8 \n\t" /*arg6 -> r5 */ \ "ld_add r6, r29, 8 \n\t" /*arg7 -> r6 */ \ "ld_add r7, r29, 8 \n\t" /*arg8 -> r7 */ \ "ld_add r8, r29, 8 \n\t" /*arg9 -> r8 */ \ "ld_add r9, r29, 8 \n\t" /*arg10 -> r9 */ \ "addi r28, sp, -8 \n\t" \ "addi sp, sp, -24 \n\t" \ "ld_add r10, r29, 8 \n\t" \ "ld r11, r29 \n\t" \ "st_add r28, r10, 8 \n\t" \ "st r28, r11 \n\t" \ VALGRIND_CALL_NOREDIR_R12 \ "addi sp, sp, 32 \n\t" \ "ld_add lr, sp, 8 \n\t" \ "move %0, r0\n" \ : /*out*/ "=r" (_res) \ : /*in*/ "r" (&_argvec[0]) \ : /*trash*/ "memory", __CALLER_SAVED_REGS); \ lval = (__typeof__(lval)) _res; \ } while (0) #endif /* PLAT_tilegx_linux */ /* ------------------------------------------------------------------ */ /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ /* */ /* ------------------------------------------------------------------ */ /* Some request codes. There are many more of these, but most are not exposed to end-user view. These are the public ones, all of the form 0x1000 + small_number. Core ones are in the range 0x00000000--0x0000ffff. The non-public ones start at 0x2000. */ /* These macros are used by tools -- they must be public, but don't embed them into other programs. */ #define VG_USERREQ_TOOL_BASE(a,b) \ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) #define VG_IS_TOOL_USERREQ(a, b, v) \ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) /* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, /* These allow any function to be called from the simulated CPU but run on the real CPU. Nb: the first arg passed to the function is always the ThreadId of the running thread! So CLIENT_CALL0 actually requires a 1 arg function, etc. */ VG_USERREQ__CLIENT_CALL0 = 0x1101, VG_USERREQ__CLIENT_CALL1 = 0x1102, VG_USERREQ__CLIENT_CALL2 = 0x1103, VG_USERREQ__CLIENT_CALL3 = 0x1104, /* Can be useful in regression testing suites -- eg. can send Valgrind's output to /dev/null and still count errors. */ VG_USERREQ__COUNT_ERRORS = 0x1201, /* Allows the client program and/or gdbserver to execute a monitor command. */ VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, /* These are useful and can be interpreted by any tool that tracks malloc() et al, by using vg_replace_malloc.c. */ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, VG_USERREQ__FREELIKE_BLOCK = 0x1302, /* Memory pool support. */ VG_USERREQ__CREATE_MEMPOOL = 0x1303, VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_FREE = 0x1306, VG_USERREQ__MEMPOOL_TRIM = 0x1307, VG_USERREQ__MOVE_MEMPOOL = 0x1308, VG_USERREQ__MEMPOOL_CHANGE = 0x1309, VG_USERREQ__MEMPOOL_EXISTS = 0x130a, /* Allow printfs to valgrind log. */ /* The first two pass the va_list argument by value, which assumes it is the same size as or smaller than a UWord, which generally isn't the case. Hence are deprecated. The second two pass the vargs by reference and so are immune to this problem. */ /* both :: char* fmt, va_list vargs (DEPRECATED) */ VG_USERREQ__PRINTF = 0x1401, VG_USERREQ__PRINTF_BACKTRACE = 0x1402, /* both :: char* fmt, va_list* vargs */ VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, /* Stack support. */ VG_USERREQ__STACK_REGISTER = 0x1501, VG_USERREQ__STACK_DEREGISTER = 0x1502, VG_USERREQ__STACK_CHANGE = 0x1503, /* Wine support */ VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, /* Querying of debug info. */ VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, /* Disable/enable error reporting level. Takes a single Word arg which is the delta to this thread's error disablement indicator. Hence 1 disables or further disables errors, and -1 moves back towards enablement. Other values are not allowed. */ VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, /* Initialise IR injection */ VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901 } Vg_ClientRequest; #if !defined(__GNUC__) # define __extension__ /* */ #endif /* Returns the number of Valgrinds this code is running under. That is, 0 if running natively, 1 if running under Valgrind, 2 if running under Valgrind which is running under another Valgrind, etc. */ #define RUNNING_ON_VALGRIND \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ VG_USERREQ__RUNNING_ON_VALGRIND, \ 0, 0, 0, 0, 0) \ /* Discard translation of code in the range [_qzz_addr .. _qzz_addr + _qzz_len - 1]. Useful if you are debugging a JITter or some such, since it provides a way to make sure valgrind will retranslate the invalidated area. Returns no value. */ #define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ _qzz_addr, _qzz_len, 0, 0, 0) /* These requests are for getting Valgrind itself to print something. Possibly with a backtrace. This is a really ugly hack. The return value is the number of characters printed, excluding the "**** " part at the start and the backtrace (if present). */ #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) /* Modern GCC will optimize the static routine out if unused, and unused attribute will shut down warnings about it. */ static int VALGRIND_PRINTF(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF(const char *format, ...) { #if defined(NVALGRIND) if (format) *(volatile const char *)format; /* avoid compiler warning */ return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } #if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) __attribute__((format(__printf__, 1, 2), __unused__)); #endif static int #if defined(_MSC_VER) __inline #endif VALGRIND_PRINTF_BACKTRACE(const char *format, ...) { #if defined(NVALGRIND) if (format) *(volatile const char *)format; /* avoid compiler warning */ return 0; #else /* NVALGRIND */ #if defined(_MSC_VER) || defined(__MINGW64__) uintptr_t _qzz_res; #else unsigned long _qzz_res; #endif va_list vargs; va_start(vargs, format); #if defined(_MSC_VER) || defined(__MINGW64__) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (uintptr_t)format, (uintptr_t)&vargs, 0, 0, 0); #else _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (unsigned long)format, (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); return (int)_qzz_res; #endif /* NVALGRIND */ } /* These requests allow control to move from the simulated CPU to the real CPU, calling an arbitary function. Note that the current ThreadId is inserted as the first argument. So this call: VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) requires f to have this signature: Word f(Word tid, Word arg1, Word arg2) where "Word" is a word-sized type. Note that these client requests are not entirely reliable. For example, if you call a function with them that subsequently calls printf(), there's a high chance Valgrind will crash. Generally, your prospects of these working are made higher if the called function does not refer to any global variables, and does not refer to any libc or other functions (printf et al). Any kind of entanglement with libc or dynamic linking is likely to have a bad outcome, for tricky reasons which we've grappled with a lot in the past. */ #define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL0, \ _qyy_fn, \ 0, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL1, \ _qyy_fn, \ _qyy_arg1, 0, 0, 0) #define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL2, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, 0, 0) #define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__CLIENT_CALL3, \ _qyy_fn, \ _qyy_arg1, _qyy_arg2, \ _qyy_arg3, 0) /* Counts the number of errors that have been recorded by a tool. Nb: the tool must record the errors with VG_(maybe_record_error)() or VG_(unique_error)() for them to be counted. */ #define VALGRIND_COUNT_ERRORS \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ 0 /* default return */, \ VG_USERREQ__COUNT_ERRORS, \ 0, 0, 0, 0, 0) /* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing when heap blocks are allocated in order to give accurate results. This happens automatically for the standard allocator functions such as malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, delete[], etc. But if your program uses a custom allocator, this doesn't automatically happen, and Valgrind will not do as well. For example, if you allocate superblocks with mmap() and then allocates chunks of the superblocks, all Valgrind's observations will be at the mmap() level and it won't know that the chunks should be considered separate entities. In Memcheck's case, that means you probably won't get heap block overrun detection (because there won't be redzones marked as unaddressable) and you definitely won't get any leak detection. The following client requests allow a custom allocator to be annotated so that it can be handled accurately by Valgrind. VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated by a malloc()-like function. For Memcheck (an illustrative case), this does two things: - It records that the block has been allocated. This means any addresses within the block mentioned in error messages will be identified as belonging to the block. It also means that if the block isn't freed it will be detected by the leak checker. - It marks the block as being addressable and undefined (if 'is_zeroed' is not set), or addressable and defined (if 'is_zeroed' is set). This controls how accesses to the block by the program are handled. 'addr' is the start of the usable block (ie. after any redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator can apply redzones -- these are blocks of padding at the start and end of each block. Adding redzones is recommended as it makes it much more likely Valgrind will spot block overruns. `is_zeroed' indicates if the memory is zeroed (or filled with another predictable value), as is the case for calloc(). VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a heap block -- that will be used by the client program -- is allocated. It's best to put it at the outermost level of the allocator if possible; for example, if you have a function my_alloc() which calls internal_alloc(), and the client request is put inside internal_alloc(), stack traces relating to the heap block will contain entries for both my_alloc() and internal_alloc(), which is probably not what you want. For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out custom blocks from within a heap block, B, that has been allocated with malloc/calloc/new/etc, then block B will be *ignored* during leak-checking -- the custom blocks will take precedence. VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For Memcheck, it does two things: - It records that the block has been deallocated. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - It marks the block as being unaddressable. VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a heap block is deallocated. VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For Memcheck, it does four things: - It records that the size of a block has been changed. This assumes that the block was annotated as having been allocated via VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - If the block shrunk, it marks the freed memory as being unaddressable. - If the block grew, it marks the new area as undefined and defines a red zone past the end of the new block. - The V-bits of the overlap between the old and the new block are preserved. VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block and before deallocation of the old block. In many cases, these three client requests will not be enough to get your allocator working well with Memcheck. More specifically, if your allocator writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call will be necessary to mark the memory as addressable just before the zeroing occurs, otherwise you'll get a lot of invalid write errors. For example, you'll need to do this if your allocator recycles freed blocks, but it zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). Alternatively, if your allocator reuses freed blocks for allocator-internal data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. Really, what's happening is a blurring of the lines between the client program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the memory should be considered unaddressable to the client program, but the allocator knows more than the rest of the client program and so may be able to safely access it. Extra client requests are necessary for Valgrind to understand the distinction between the allocator and the rest of the program. Ignored if addr == 0. */ #define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ addr, sizeB, rzB, is_zeroed, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ addr, oldSizeB, newSizeB, rzB, 0) /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. Ignored if addr == 0. */ #define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ addr, rzB, 0, 0, 0) /* Create a memory pool. */ #define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, 0, 0) /* Create a memory pool with some flags specifying extended behaviour. When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL. The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used by the application as superblocks to dole out MALLOC_LIKE blocks using VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels" pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC. The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK. Note that the association between the pool and the second level blocks is implicit : second level blocks will be located inside first level blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag for such 2 levels pools, as otherwise valgrind will detect overlapping memory blocks, and will abort execution (e.g. during leak search). Such a meta pool can also be marked as an 'auto free' pool using the flag VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE will automatically free the second level blocks that are contained inside the first level block freed with VALGRIND_MEMPOOL_FREE. In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls to VALGRIND_FREELIKE_BLOCK for all the second level blocks included in the first level block. Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag without the VALGRIND_MEMPOOL_METAPOOL flag. */ #define VALGRIND_MEMPOOL_AUTO_FREE 1 #define VALGRIND_MEMPOOL_METAPOOL 2 #define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ pool, rzB, is_zeroed, flags, 0) /* Destroy a memory pool. */ #define VALGRIND_DESTROY_MEMPOOL(pool) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ pool, 0, 0, 0, 0) /* Associate a piece of memory with a memory pool. */ #define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ pool, addr, size, 0, 0) /* Disassociate a piece of memory from a memory pool. */ #define VALGRIND_MEMPOOL_FREE(pool, addr) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ pool, addr, 0, 0, 0) /* Disassociate any pieces outside a particular range. */ #define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ pool, addr, size, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ poolA, poolB, 0, 0, 0) /* Resize and/or move a piece associated with a memory pool. */ #define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ pool, addrA, addrB, size, 0) /* Return 1 if a mempool exists, else 0. */ #define VALGRIND_MEMPOOL_EXISTS(pool) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MEMPOOL_EXISTS, \ pool, 0, 0, 0, 0) /* Mark a piece of memory as being a stack. Returns a stack id. start is the lowest addressable stack byte, end is the highest addressable stack byte. */ #define VALGRIND_STACK_REGISTER(start, end) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__STACK_REGISTER, \ start, end, 0, 0, 0) /* Unmark the piece of memory associated with a stack id as being a stack. */ #define VALGRIND_STACK_DEREGISTER(id) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ id, 0, 0, 0, 0) /* Change the start and end address of the stack id. start is the new lowest addressable stack byte, end is the new highest addressable stack byte. */ #define VALGRIND_STACK_CHANGE(id, start, end) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ id, start, end, 0, 0) /* Load PDB debug info for Wine PE image_map. */ #define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ fd, ptr, total_size, delta, 0) /* Map a code address to a source file name and line number. buf64 must point to a 64-byte buffer in the caller's address space. The result will be dumped in there and is guaranteed to be zero terminated. If no info is found, the first byte is set to zero. */ #define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ VG_USERREQ__MAP_IP_TO_SRCLOC, \ addr, buf64, 0, 0, 0) /* Disable error reporting for this thread. Behaves in a stack like way, so you can safely call this multiple times provided that VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times to re-enable reporting. The first call of this macro disables reporting. Subsequent calls have no effect except to increase the number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable reporting. Child threads do not inherit this setting from their parents -- they are always created with reporting enabled. */ #define VALGRIND_DISABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ 1, 0, 0, 0, 0) /* Re-enable error reporting, as per comments on VALGRIND_DISABLE_ERROR_REPORTING. */ #define VALGRIND_ENABLE_ERROR_REPORTING \ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ -1, 0, 0, 0, 0) /* Execute a monitor command from the client program. If a connection is opened with GDB, the output will be sent according to the output mode set for vgdb. If no connection is opened, output will go to the log output. Returns 1 if command not recognised, 0 otherwise. */ #define VALGRIND_MONITOR_COMMAND(command) \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ command, 0, 0, 0, 0) #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux #undef PLAT_ppc64be_linux #undef PLAT_ppc64le_linux #undef PLAT_arm_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux #undef PLAT_tilegx_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris #endif /* __VALGRIND_H */ pmdk-1.4.1/src/common/valgrind_internal.h000066400000000000000000000272751331545616200204250ustar00rootroot00000000000000/* * Copyright 2015-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * valgrind_internal.h -- internal definitions for valgrind macros */ #ifndef PMDK_VALGRIND_INTERNAL_H #define PMDK_VALGRIND_INTERNAL_H 1 #ifndef _WIN32 #ifndef VALGRIND_ENABLED #define VALGRIND_ENABLED 1 #endif #endif #if VALGRIND_ENABLED #define VG_PMEMCHECK_ENABLED 1 #define VG_HELGRIND_ENABLED 1 #define VG_MEMCHECK_ENABLED 1 #define VG_DRD_ENABLED 1 #endif #if VG_PMEMCHECK_ENABLED || VG_HELGRIND_ENABLED || VG_MEMCHECK_ENABLED || \ VG_DRD_ENABLED #define ANY_VG_TOOL_ENABLED 1 #else #define ANY_VG_TOOL_ENABLED 0 #endif #if ANY_VG_TOOL_ENABLED extern unsigned _On_valgrind; #define On_valgrind __builtin_expect(_On_valgrind, 0) #include "valgrind/valgrind.h" #else #define On_valgrind (0) #endif #if VG_HELGRIND_ENABLED #include "valgrind/helgrind.h" #endif #if VG_DRD_ENABLED #include "valgrind/drd.h" #endif #if VG_HELGRIND_ENABLED || VG_DRD_ENABLED #define VALGRIND_ANNOTATE_HAPPENS_BEFORE(obj) do {\ if (On_valgrind) \ ANNOTATE_HAPPENS_BEFORE((obj));\ } while (0) #define VALGRIND_ANNOTATE_HAPPENS_AFTER(obj) do {\ if (On_valgrind) \ ANNOTATE_HAPPENS_AFTER((obj));\ } while (0) #define VALGRIND_ANNOTATE_NEW_MEMORY(addr, size) do {\ if (On_valgrind) \ ANNOTATE_NEW_MEMORY((addr), (size));\ } while (0) #define VALGRIND_ANNOTATE_IGNORE_READS_BEGIN() do {\ if (On_valgrind) \ ANNOTATE_IGNORE_READS_BEGIN();\ } while (0) #define VALGRIND_ANNOTATE_IGNORE_READS_END() do {\ if (On_valgrind) \ ANNOTATE_IGNORE_READS_END();\ } while (0) #define VALGRIND_ANNOTATE_IGNORE_WRITES_BEGIN() do {\ if (On_valgrind) \ ANNOTATE_IGNORE_WRITES_BEGIN();\ } while (0) #define VALGRIND_ANNOTATE_IGNORE_WRITES_END() do {\ if (On_valgrind) \ ANNOTATE_IGNORE_WRITES_END();\ } while (0) #else #define VALGRIND_ANNOTATE_HAPPENS_BEFORE(obj) do { (void)(obj); } while (0) #define VALGRIND_ANNOTATE_HAPPENS_AFTER(obj) do { (void)(obj); } while (0) #define VALGRIND_ANNOTATE_NEW_MEMORY(addr, size) do {\ (void) (addr);\ (void) (size);\ } while (0) #define VALGRIND_ANNOTATE_IGNORE_READS_BEGIN() do {} while (0) #define VALGRIND_ANNOTATE_IGNORE_READS_END() do {} while (0) #define VALGRIND_ANNOTATE_IGNORE_WRITES_BEGIN() do {} while (0) #define VALGRIND_ANNOTATE_IGNORE_WRITES_END() do {} while (0) #endif #if VG_PMEMCHECK_ENABLED #include "valgrind/pmemcheck.h" #define VALGRIND_REGISTER_PMEM_MAPPING(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_REGISTER_PMEM_MAPPING((addr), (len));\ } while (0) #define VALGRIND_REGISTER_PMEM_FILE(desc, base_addr, size, offset) do {\ if (On_valgrind)\ VALGRIND_PMC_REGISTER_PMEM_FILE((desc), (base_addr), (size), \ (offset));\ } while (0) #define VALGRIND_REMOVE_PMEM_MAPPING(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_REMOVE_PMEM_MAPPING((addr), (len));\ } while (0) #define VALGRIND_CHECK_IS_PMEM_MAPPING(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_CHECK_IS_PMEM_MAPPING((addr), (len));\ } while (0) #define VALGRIND_PRINT_PMEM_MAPPINGS do {\ if (On_valgrind)\ VALGRIND_PMC_PRINT_PMEM_MAPPINGS;\ } while (0) #define VALGRIND_DO_FLUSH(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_DO_FLUSH((addr), (len));\ } while (0) #define VALGRIND_DO_FENCE do {\ if (On_valgrind)\ VALGRIND_PMC_DO_FENCE;\ } while (0) #define VALGRIND_DO_COMMIT do {\ if (On_valgrind)\ VALGRIND_PMC_DO_COMMIT;\ } while (0) #define VALGRIND_DO_PERSIST(addr, len) do {\ if (On_valgrind) {\ VALGRIND_PMC_DO_FLUSH((addr), (len));\ VALGRIND_PMC_DO_FENCE;\ VALGRIND_PMC_DO_COMMIT;\ VALGRIND_PMC_DO_FENCE;\ }\ } while (0) #define VALGRIND_SET_CLEAN(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_SET_CLEAN(addr, len);\ } while (0) #define VALGRIND_WRITE_STATS do {\ if (On_valgrind)\ VALGRIND_PMC_WRITE_STATS;\ } while (0) #define VALGRIND_LOG_STORES do {\ if (On_valgrind)\ VALGRIND_PMC_LOG_STORES;\ } while (0) #define VALGRIND_NO_LOG_STORES do {\ if (On_valgrind)\ VALGRIND_PMC_NO_LOG_STORES;\ } while (0) #define VALGRIND_ADD_LOG_REGION(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_ADD_LOG_REGION((addr), (len));\ } while (0) #define VALGRIND_REMOVE_LOG_REGION(addr, len) do {\ if (On_valgrind)\ \ VALGRIND_PMC_REMOVE_LOG_REGION((addr), (len));\ } while (0) #define VALGRIND_FULL_REORDER do {\ if (On_valgrind)\ VALGRIND_PMC_FULL_REORDER;\ } while (0) #define VALGRIND_PARTIAL_REORDER do {\ if (On_valgrind)\ VALGRIND_PMC_PARTIAL_REORDER;\ } while (0) #define VALGRIND_ONLY_FAULT do {\ if (On_valgrind)\ VALGRIND_PMC_ONLY_FAULT;\ } while (0) #define VALGRIND_STOP_REORDER_FAULT do {\ if (On_valgrind)\ VALGRIND_PMC_STOP_REORDER_FAULT;\ } while (0) #define VALGRIND_START_TX do {\ if (On_valgrind)\ VALGRIND_PMC_START_TX;\ } while (0) #define VALGRIND_START_TX_N(txn) do {\ if (On_valgrind)\ VALGRIND_PMC_START_TX_N(txn);\ } while (0) #define VALGRIND_END_TX do {\ if (On_valgrind)\ VALGRIND_PMC_END_TX;\ } while (0) #define VALGRIND_END_TX_N(txn) do {\ if (On_valgrind)\ VALGRIND_PMC_END_TX_N(txn);\ } while (0) #define VALGRIND_ADD_TO_TX(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_ADD_TO_TX(addr, len);\ } while (0) #define VALGRIND_ADD_TO_TX_N(txn, addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_ADD_TO_TX_N(txn, addr, len);\ } while (0) #define VALGRIND_REMOVE_FROM_TX(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_REMOVE_FROM_TX(addr, len);\ } while (0) #define VALGRIND_REMOVE_FROM_TX_N(txn, addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_REMOVE_FROM_TX_N(txn, addr, len);\ } while (0) #define VALGRIND_ADD_TO_GLOBAL_TX_IGNORE(addr, len) do {\ if (On_valgrind)\ VALGRIND_PMC_ADD_TO_GLOBAL_TX_IGNORE(addr, len);\ } while (0) #else #define VALGRIND_REGISTER_PMEM_MAPPING(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_REGISTER_PMEM_FILE(desc, base_addr, size, offset) do {\ (void) (desc);\ (void) (base_addr);\ (void) (size);\ (void) (offset);\ } while (0) #define VALGRIND_REMOVE_PMEM_MAPPING(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_CHECK_IS_PMEM_MAPPING(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_PRINT_PMEM_MAPPINGS do {} while (0) #define VALGRIND_DO_FLUSH(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_DO_FENCE do {} while (0) #define VALGRIND_DO_COMMIT do {} while (0) #define VALGRIND_DO_PERSIST(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_SET_CLEAN(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_WRITE_STATS do {} while (0) #define VALGRIND_LOG_STORES do {} while (0) #define VALGRIND_NO_LOG_STORES do {} while (0) #define VALGRIND_ADD_LOG_REGION(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_REMOVE_LOG_REGION(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_FULL_REORDER do {} while (0) #define VALGRIND_PARTIAL_REORDER do {} while (0) #define VALGRIND_ONLY_FAULT do {} while (0) #define VALGRIND_STOP_REORDER_FAULT do {} while (0) #define VALGRIND_START_TX do {} while (0) #define VALGRIND_START_TX_N(txn) do { (void) (txn); } while (0) #define VALGRIND_END_TX do {} while (0) #define VALGRIND_END_TX_N(txn) do {\ (void) (txn);\ } while (0) #define VALGRIND_ADD_TO_TX(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_ADD_TO_TX_N(txn, addr, len) do {\ (void) (txn);\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_REMOVE_FROM_TX(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_REMOVE_FROM_TX_N(txn, addr, len) do {\ (void) (txn);\ (void) (addr);\ (void) (len);\ } while (0) #define VALGRIND_ADD_TO_GLOBAL_TX_IGNORE(addr, len) do {\ (void) (addr);\ (void) (len);\ } while (0) #endif #if VG_MEMCHECK_ENABLED #include "valgrind/memcheck.h" #define VALGRIND_DO_DISABLE_ERROR_REPORTING do {\ if (On_valgrind)\ VALGRIND_DISABLE_ERROR_REPORTING;\ } while (0) #define VALGRIND_DO_ENABLE_ERROR_REPORTING do {\ if (On_valgrind)\ VALGRIND_ENABLE_ERROR_REPORTING;\ } while (0) #define VALGRIND_DO_CREATE_MEMPOOL(heap, rzB, is_zeroed) do {\ if (On_valgrind)\ VALGRIND_CREATE_MEMPOOL(heap, rzB, is_zeroed);\ } while (0) #define VALGRIND_DO_DESTROY_MEMPOOL(heap) do {\ if (On_valgrind)\ VALGRIND_DESTROY_MEMPOOL(heap);\ } while (0) #define VALGRIND_DO_MEMPOOL_ALLOC(heap, addr, size) do {\ if (On_valgrind)\ VALGRIND_MEMPOOL_ALLOC(heap, addr, size);\ } while (0) #define VALGRIND_DO_MEMPOOL_FREE(heap, addr) do {\ if (On_valgrind)\ VALGRIND_MEMPOOL_FREE(heap, addr);\ } while (0) #define VALGRIND_DO_MEMPOOL_CHANGE(heap, addrA, addrB, size) do {\ if (On_valgrind)\ VALGRIND_MEMPOOL_CHANGE(heap, addrA, addrB, size);\ } while (0) #define VALGRIND_DO_MAKE_MEM_DEFINED(addr, len) do {\ if (On_valgrind)\ VALGRIND_MAKE_MEM_DEFINED(addr, len);\ } while (0) #define VALGRIND_DO_MAKE_MEM_UNDEFINED(addr, len) do {\ if (On_valgrind)\ VALGRIND_MAKE_MEM_UNDEFINED(addr, len);\ } while (0) #define VALGRIND_DO_MAKE_MEM_NOACCESS(addr, len) do {\ if (On_valgrind)\ VALGRIND_MAKE_MEM_NOACCESS(addr, len);\ } while (0) #define VALGRIND_DO_CHECK_MEM_IS_ADDRESSABLE(addr, len) do {\ if (On_valgrind)\ VALGRIND_CHECK_MEM_IS_ADDRESSABLE(addr, len);\ } while (0) #else #define VALGRIND_DO_DISABLE_ERROR_REPORTING do {} while (0) #define VALGRIND_DO_ENABLE_ERROR_REPORTING do {} while (0) #define VALGRIND_DO_CREATE_MEMPOOL(heap, rzB, is_zeroed)\ do { (void) (heap); (void) (rzB); (void) (is_zeroed); } while (0) #define VALGRIND_DO_DESTROY_MEMPOOL(heap)\ do { (void) (heap); } while (0) #define VALGRIND_DO_MEMPOOL_ALLOC(heap, addr, size)\ do { (void) (heap); (void) (addr); (void) (size); } while (0) #define VALGRIND_DO_MEMPOOL_FREE(heap, addr)\ do { (void) (heap); (void) (addr); } while (0) #define VALGRIND_DO_MEMPOOL_CHANGE(heap, addrA, addrB, size)\ do {\ (void) (heap); (void) (addrA); (void) (addrB); (void) (size);\ } while (0) #define VALGRIND_DO_MAKE_MEM_DEFINED(addr, len)\ do { (void) (addr); (void) (len); } while (0) #define VALGRIND_DO_MAKE_MEM_UNDEFINED(addr, len)\ do { (void) (addr); (void) (len); } while (0) #define VALGRIND_DO_MAKE_MEM_NOACCESS(addr, len)\ do { (void) (addr); (void) (len); } while (0) #define VALGRIND_DO_CHECK_MEM_IS_ADDRESSABLE(addr, len)\ do { (void) (addr); (void) (len); } while (0) #endif #endif pmdk-1.4.1/src/common/vec.h000066400000000000000000000074101331545616200154650ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * vec.h -- vector interface */ #ifndef PMDK_VEC_H #define PMDK_VEC_H 1 #define VEC_GROW_SIZE (64) #define VEC(name, type)\ struct name {\ type *buffer;\ size_t size;\ size_t capacity;\ } #define VEC_INITIALIZER {NULL, 0, 0} #define VEC_INIT(vec) do {\ (vec)->buffer = NULL;\ (vec)->size = 0;\ (vec)->capacity = 0;\ } while (0) #define VEC_RESERVE(vec, ncapacity) do {\ if ((ncapacity) > (vec)->size) {\ void *tbuf = Realloc((vec)->buffer,\ sizeof(*(vec)->buffer) * (ncapacity));\ ASSERTne(tbuf, NULL);\ /* there's no way to return a value from a macro in MSVC... */\ (vec)->buffer = tbuf;\ (vec)->capacity = ncapacity;\ }\ } while (0) #define VEC_POP_BACK(vec) do {\ (vec)->size -= 1;\ } while (0) #define VEC_FRONT(vec)\ (vec)->buffer[0] #define VEC_BACK(vec)\ (vec)->buffer[(vec)->size - 1] #define VEC_ERASE_BY_POS(vec, pos) do {\ (vec)->buffer[(pos)] = VEC_BACK(vec);\ VEC_POP_BACK(vec);\ } while (0) #define VEC_ERASE_BY_PTR(vec, element) do {\ ptrdiff_t elpos = (uintptr_t)(element) - (uintptr_t)((vec)->buffer);\ elpos /= sizeof(*element);\ VEC_ERASE_BY_POS(vec, elpos);\ } while (0) #define VEC_PUSH_BACK(vec, element) do {\ if ((vec)->capacity == (vec)->size)\ VEC_RESERVE((vec), ((vec)->capacity + VEC_GROW_SIZE));\ (vec)->buffer[(vec)->size++] = (element);\ } while (0) /* doesn't work on MSVC */ #define VEC_EMPLACE_BACK(vec, ...) do {\ if ((vec)->capacity == (vec)->size)\ VEC_RESERVE((vec), (vec)->capacity + VEC_GROW_SIZE);\ (vec)->buffer[(vec)->size++] = (typeof(*(vec)->buffer)) {__VA_ARGS__};\ } while (0) #define VEC_FOREACH(el, vec)\ for (size_t _vec_i = 0;\ _vec_i < (vec)->size && ((el = (vec)->buffer[_vec_i]), 1);\ ++_vec_i) #define VEC_FOREACH_BY_POS(elpos, vec)\ for (elpos = 0; elpos < (vec)->size; ++elpos) #define VEC_FOREACH_BY_PTR(el, vec)\ for (size_t _vec_i = 0;\ _vec_i < (vec)->size && ((el = &(vec)->buffer[_vec_i]), 1);\ ++_vec_i) #define VEC_SIZE(vec)\ ((vec)->size) #define VEC_CAPACITY(vec)\ ((vec)->capacity) #define VEC_ARR(vec)\ ((vec)->buffer) #define VEC_GET(vec, id)\ (&(vec)->buffer[id]) #define VEC_CLEAR(vec) do {\ (vec)->size = 0;\ } while (0) #define VEC_DELETE(vec) do {\ Free((vec)->buffer);\ } while (0) #endif /* PMDK_VEC_H */ pmdk-1.4.1/src/examples/000077500000000000000000000000001331545616200150635ustar00rootroot00000000000000pmdk-1.4.1/src/examples/.gitignore000066400000000000000000000000041331545616200170450ustar00rootroot00000000000000*.o pmdk-1.4.1/src/examples/Examples.sln000066400000000000000000000627541331545616200173750ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{0CC6D525-806E-433F-AB4A-6CFD546418B1}" ProjectSection(SolutionItems) = preProject examples\ex_common.h = examples\ex_common.h EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmem", "libpmem", "{1434B17C-6165-4D42-BEA1-5A7730D5A6BB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemobj_cpp", "libpmemobj_cpp", "{52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "string_store_tx", "string_store_tx", "{6D63CDF1-F62C-4614-AD8A-95B0A63AA070}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{853D45D8-980C-4991-B62A-DAC6FD245402}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemlog", "libpmemlog", "{91C30620-70CA-46C7-AC71-71F3C602690E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "map", "map", "{BD6CC700-B36B-435B-BAF9-FC5AFCD766C9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "string_store", "string_store", "{BFEDF709-A700-4769-9056-ACA934D828A8}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemblk", "libpmemblk", "{C721EFBD-45DC-479E-9B99-E62FCC1FC6E5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "string_store_tx_type", "string_store_tx_type", "{E3229AF7-1FA2-4632-BB0B-B74F709F1A33}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libvmem", "libvmem", "{EA0D2458-5FCD-4DAB-B07D-229327B98BEB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmemobj", "libpmemobj", "{F42C09CD-ABA5-4DA9-8383-5EA40FA4D763}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "full_copy", "libpmem\full_copy.vcxproj", "{0287C3DC-AE03-4714-AAFF-C52F062ECA6F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "libpmem\manpage.vcxproj", "{FCD0587A-4504-4F5E-8E9C-468CC03D250A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_copy", "libpmem\simple_copy.vcxproj", "{D062166F-0EC7-4C13-A772-0C7157EEFE41}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "libvmem\manpage.vcxproj", "{C84633F5-05B1-4AC1-A074-104D1DB2A91E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_checkin", "libpmemblk\assetdb\asset_checkin.vcxproj", "{581B3A58-F3F0-4765-91E5-D0C82816A528}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_checkout", "libpmemblk\assetdb\asset_checkout.vcxproj", "{513C4CFA-BD5B-4470-BA93-F6D43778A754}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_list", "libpmemblk\assetdb\asset_list.vcxproj", "{8008010F-8718-4C5F-86B2-195AEBF73422}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asset_load", "libpmemblk\assetdb\asset_load.vcxproj", "{C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "libpmemblk\manpage.vcxproj", "{8010BBB0-C71B-4EFF-95EB-65C01E5EC197}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "addlog", "libpmemlog\logfile\addlog.vcxproj", "{A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "printlog", "libpmemlog\logfile\printlog.vcxproj", "{C3CEE34C-29E0-4A22-B258-3FBAF662AA19}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "libpmemlog\manpage.vcxproj", "{9FF51F3E-AF36-4F45-A797-C5F03A090298}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_snippets", "libpmemobj++\doc_snippets\doc_snippets.vcxproj", "{8DB4158E-96EE-4DE5-A425-C9638F50B9ED}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_cli", "libpmemobj++\map_cli\map_cli.vcxproj", "{9D1C3F29-1268-4241-BEFB-89D2859C62D3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "queue", "libpmemobj++\queue\queue.vcxproj", "{A6CC801B-CF30-4703-BC54-3E21F90B787D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "array", "libpmemobj\array\array.vcxproj", "{7264C8F6-73FB-4830-9306-1558D3EAC71B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "btree", "libpmemobj\btree.vcxproj", "{0FB8F0FD-276C-413B-97A8-67ABE0C9043B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fifo", "libpmemobj\linkedlist\fifo.vcxproj", "{D3A99F36-4B72-4766-ABCD-CCEDC26DD139}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lists", "libpmemobj\lists.vcxproj", "{2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "manpage", "libpmemobj\manpage.vcxproj", "{EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pi", "libpmemobj\pi.vcxproj", "{11D76FBC-DFAA-4B31-9DB0-206E171E3F94}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemblk", "libpmemobj\pmemblk\obj_pmemblk.vcxproj", "{8C42CA7C-1543-4F1B-A55F-28CD419C7D35}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog", "libpmemobj\pmemlog\obj_pmemlog.vcxproj", "{60206D22-E132-4695-8486-10BECA32C5CC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog_macros", "libpmemobj\pmemlog\obj_pmemlog_macros.vcxproj", "{06877FED-15BA-421F-85C9-1A964FB97446}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog_minimal", "libpmemobj\pmemlog\obj_pmemlog_minimal.vcxproj", "{0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmemlog_simple", "libpmemobj\pmemlog\obj_pmemlog_simple.vcxproj", "{5DB2E259-0D19-4A89-B8EC-B2912F39924D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reader", "libpmemobj\string_store\reader.vcxproj", "{0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "writer", "libpmemobj\string_store\writer.vcxproj", "{F5D850C9-D353-4B84-99BC-E336C231018C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reader", "libpmemobj\string_store_tx\reader.vcxproj", "{59D7A9CD-9912-40E4-96E1-8A873F777F62}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "writer", "libpmemobj\string_store_tx\writer.vcxproj", "{7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reader", "libpmemobj\string_store_tx_type\reader.vcxproj", "{74D655D5-F661-4887-A1EB-5A6222AF5FCA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "writer", "libpmemobj\string_store_tx_type\writer.vcxproj", "{1EB3DE5B-6357-498D-8CAC-EEC0209EA454}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "btree_map", "libpmemobj\tree_map\btree_map.vcxproj", "{79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctree_map", "libpmemobj\tree_map\ctree_map.vcxproj", "{BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rbtree_map", "libpmemobj\tree_map\rbtree_map.vcxproj", "{17A4B817-68B1-4719-A9EF-BD8FAB747DE6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtree_map", "libpmemobj\tree_map\rtree_map.vcxproj", "{3ED56E55-84A6-422C-A8D4-A8439FB8F245}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_map", "libpmemobj\list_map\list_map.vcxproj", "{3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hashmap_atomic", "libpmemobj\hashmap\hashmap_atomic.vcxproj", "{F5E2F6C4-19BA-497A-B754-232E469BE647}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hashmap_tx", "libpmemobj\hashmap\hashmap_tx.vcxproj", "{D93A2683-6D99-4F18-B378-91195D23E007}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmap", "libpmemobj\map\libmap.vcxproj", "{49A7CC5A-D5E7-4A07-917F-C6918B982BE8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_store", "libpmemobj\map\data_store.vcxproj", "{5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapcli", "libpmemobj\map\mapcli.vcxproj", "{BB248BAC-6E1B-433C-A254-75140A273AB5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmpong", "libpmemobj++\pmpong\pmpong.vcxproj", "{C6E9D8C2-D5C1-441B-95ED-378E10DC5723}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Debug|x64.ActiveCfg = Debug|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Debug|x64.Build.0 = Debug|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Release|x64.ActiveCfg = Release|x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F}.Release|x64.Build.0 = Release|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Debug|x64.ActiveCfg = Debug|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Debug|x64.Build.0 = Debug|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Release|x64.ActiveCfg = Release|x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A}.Release|x64.Build.0 = Release|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Debug|x64.ActiveCfg = Debug|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Debug|x64.Build.0 = Debug|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Release|x64.ActiveCfg = Release|x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41}.Release|x64.Build.0 = Release|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Debug|x64.ActiveCfg = Debug|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Debug|x64.Build.0 = Debug|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Release|x64.ActiveCfg = Release|x64 {C84633F5-05B1-4AC1-A074-104D1DB2A91E}.Release|x64.Build.0 = Release|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Debug|x64.ActiveCfg = Debug|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Debug|x64.Build.0 = Debug|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Release|x64.ActiveCfg = Release|x64 {581B3A58-F3F0-4765-91E5-D0C82816A528}.Release|x64.Build.0 = Release|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Debug|x64.ActiveCfg = Debug|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Debug|x64.Build.0 = Debug|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Release|x64.ActiveCfg = Release|x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754}.Release|x64.Build.0 = Release|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Debug|x64.ActiveCfg = Debug|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Debug|x64.Build.0 = Debug|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Release|x64.ActiveCfg = Release|x64 {8008010F-8718-4C5F-86B2-195AEBF73422}.Release|x64.Build.0 = Release|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Debug|x64.ActiveCfg = Debug|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Debug|x64.Build.0 = Debug|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Release|x64.ActiveCfg = Release|x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC}.Release|x64.Build.0 = Release|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Debug|x64.ActiveCfg = Debug|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Debug|x64.Build.0 = Debug|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Release|x64.ActiveCfg = Release|x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197}.Release|x64.Build.0 = Release|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Debug|x64.ActiveCfg = Debug|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Debug|x64.Build.0 = Debug|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Release|x64.ActiveCfg = Release|x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2}.Release|x64.Build.0 = Release|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Debug|x64.ActiveCfg = Debug|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Debug|x64.Build.0 = Debug|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Release|x64.ActiveCfg = Release|x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19}.Release|x64.Build.0 = Release|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Debug|x64.ActiveCfg = Debug|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Debug|x64.Build.0 = Debug|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Release|x64.ActiveCfg = Release|x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298}.Release|x64.Build.0 = Release|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Debug|x64.ActiveCfg = Debug|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Debug|x64.Build.0 = Debug|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Release|x64.ActiveCfg = Release|x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED}.Release|x64.Build.0 = Release|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Debug|x64.ActiveCfg = Debug|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Debug|x64.Build.0 = Debug|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Release|x64.ActiveCfg = Release|x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3}.Release|x64.Build.0 = Release|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Debug|x64.ActiveCfg = Debug|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Debug|x64.Build.0 = Debug|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Release|x64.ActiveCfg = Release|x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D}.Release|x64.Build.0 = Release|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Debug|x64.ActiveCfg = Debug|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Debug|x64.Build.0 = Debug|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Release|x64.ActiveCfg = Release|x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B}.Release|x64.Build.0 = Release|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Debug|x64.ActiveCfg = Debug|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Debug|x64.Build.0 = Debug|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Release|x64.ActiveCfg = Release|x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B}.Release|x64.Build.0 = Release|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Debug|x64.ActiveCfg = Debug|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Debug|x64.Build.0 = Debug|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Release|x64.ActiveCfg = Release|x64 {D3A99F36-4B72-4766-ABCD-CCEDC26DD139}.Release|x64.Build.0 = Release|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Debug|x64.ActiveCfg = Debug|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Debug|x64.Build.0 = Debug|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Release|x64.ActiveCfg = Release|x64 {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462}.Release|x64.Build.0 = Release|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Debug|x64.ActiveCfg = Debug|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Debug|x64.Build.0 = Debug|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Release|x64.ActiveCfg = Release|x64 {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB}.Release|x64.Build.0 = Release|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Debug|x64.ActiveCfg = Debug|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Debug|x64.Build.0 = Debug|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Release|x64.ActiveCfg = Release|x64 {11D76FBC-DFAA-4B31-9DB0-206E171E3F94}.Release|x64.Build.0 = Release|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Debug|x64.ActiveCfg = Debug|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Debug|x64.Build.0 = Debug|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Release|x64.ActiveCfg = Release|x64 {8C42CA7C-1543-4F1B-A55F-28CD419C7D35}.Release|x64.Build.0 = Release|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Debug|x64.ActiveCfg = Debug|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Debug|x64.Build.0 = Debug|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Release|x64.ActiveCfg = Release|x64 {60206D22-E132-4695-8486-10BECA32C5CC}.Release|x64.Build.0 = Release|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Debug|x64.ActiveCfg = Debug|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Debug|x64.Build.0 = Debug|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Release|x64.ActiveCfg = Release|x64 {06877FED-15BA-421F-85C9-1A964FB97446}.Release|x64.Build.0 = Release|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Debug|x64.ActiveCfg = Debug|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Debug|x64.Build.0 = Debug|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Release|x64.ActiveCfg = Release|x64 {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235}.Release|x64.Build.0 = Release|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Debug|x64.ActiveCfg = Debug|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Debug|x64.Build.0 = Debug|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Release|x64.ActiveCfg = Release|x64 {5DB2E259-0D19-4A89-B8EC-B2912F39924D}.Release|x64.Build.0 = Release|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Debug|x64.ActiveCfg = Debug|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Debug|x64.Build.0 = Debug|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Release|x64.ActiveCfg = Release|x64 {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03}.Release|x64.Build.0 = Release|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Debug|x64.ActiveCfg = Debug|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Debug|x64.Build.0 = Debug|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Release|x64.ActiveCfg = Release|x64 {F5D850C9-D353-4B84-99BC-E336C231018C}.Release|x64.Build.0 = Release|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Debug|x64.ActiveCfg = Debug|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Debug|x64.Build.0 = Debug|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Release|x64.ActiveCfg = Release|x64 {59D7A9CD-9912-40E4-96E1-8A873F777F62}.Release|x64.Build.0 = Release|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Debug|x64.ActiveCfg = Debug|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Debug|x64.Build.0 = Debug|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Release|x64.ActiveCfg = Release|x64 {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF}.Release|x64.Build.0 = Release|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Debug|x64.ActiveCfg = Debug|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Debug|x64.Build.0 = Debug|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Release|x64.ActiveCfg = Release|x64 {74D655D5-F661-4887-A1EB-5A6222AF5FCA}.Release|x64.Build.0 = Release|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Debug|x64.ActiveCfg = Debug|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Debug|x64.Build.0 = Debug|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Release|x64.ActiveCfg = Release|x64 {1EB3DE5B-6357-498D-8CAC-EEC0209EA454}.Release|x64.Build.0 = Release|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Debug|x64.ActiveCfg = Debug|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Debug|x64.Build.0 = Debug|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Release|x64.ActiveCfg = Release|x64 {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9}.Release|x64.Build.0 = Release|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Debug|x64.ActiveCfg = Debug|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Debug|x64.Build.0 = Debug|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Release|x64.ActiveCfg = Release|x64 {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F}.Release|x64.Build.0 = Release|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Debug|x64.ActiveCfg = Debug|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Debug|x64.Build.0 = Debug|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Release|x64.ActiveCfg = Release|x64 {17A4B817-68B1-4719-A9EF-BD8FAB747DE6}.Release|x64.Build.0 = Release|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Debug|x64.ActiveCfg = Debug|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Debug|x64.Build.0 = Debug|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Release|x64.ActiveCfg = Release|x64 {3ED56E55-84A6-422C-A8D4-A8439FB8F245}.Release|x64.Build.0 = Release|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Debug|x64.ActiveCfg = Debug|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Debug|x64.Build.0 = Debug|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Release|x64.ActiveCfg = Release|x64 {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180}.Release|x64.Build.0 = Release|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Debug|x64.ActiveCfg = Debug|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Debug|x64.Build.0 = Debug|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Release|x64.ActiveCfg = Release|x64 {F5E2F6C4-19BA-497A-B754-232E469BE647}.Release|x64.Build.0 = Release|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Debug|x64.ActiveCfg = Debug|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Debug|x64.Build.0 = Debug|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Release|x64.ActiveCfg = Release|x64 {D93A2683-6D99-4F18-B378-91195D23E007}.Release|x64.Build.0 = Release|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Debug|x64.ActiveCfg = Debug|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Debug|x64.Build.0 = Debug|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Release|x64.ActiveCfg = Release|x64 {49A7CC5A-D5E7-4A07-917F-C6918B982BE8}.Release|x64.Build.0 = Release|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Debug|x64.ActiveCfg = Debug|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Debug|x64.Build.0 = Debug|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Release|x64.ActiveCfg = Release|x64 {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3}.Release|x64.Build.0 = Release|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Debug|x64.ActiveCfg = Debug|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Debug|x64.Build.0 = Debug|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Release|x64.ActiveCfg = Release|x64 {BB248BAC-6E1B-433C-A254-75140A273AB5}.Release|x64.Build.0 = Release|x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723}.Debug|x64.ActiveCfg = Debug|x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723}.Debug|x64.Build.0 = Debug|x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723}.Release|x64.ActiveCfg = Release|x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {0CC6D525-806E-433F-AB4A-6CFD546418B1} = {853D45D8-980C-4991-B62A-DAC6FD245402} {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {6D63CDF1-F62C-4614-AD8A-95B0A63AA070} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {91C30620-70CA-46C7-AC71-71F3C602690E} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {BFEDF709-A700-4769-9056-ACA934D828A8} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {EA0D2458-5FCD-4DAB-B07D-229327B98BEB} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} = {0CC6D525-806E-433F-AB4A-6CFD546418B1} {0287C3DC-AE03-4714-AAFF-C52F062ECA6F} = {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} {FCD0587A-4504-4F5E-8E9C-468CC03D250A} = {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} {D062166F-0EC7-4C13-A772-0C7157EEFE41} = {1434B17C-6165-4D42-BEA1-5A7730D5A6BB} {C84633F5-05B1-4AC1-A074-104D1DB2A91E} = {EA0D2458-5FCD-4DAB-B07D-229327B98BEB} {581B3A58-F3F0-4765-91E5-D0C82816A528} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {513C4CFA-BD5B-4470-BA93-F6D43778A754} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {8008010F-8718-4C5F-86B2-195AEBF73422} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {8010BBB0-C71B-4EFF-95EB-65C01E5EC197} = {C721EFBD-45DC-479E-9B99-E62FCC1FC6E5} {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2} = {91C30620-70CA-46C7-AC71-71F3C602690E} {C3CEE34C-29E0-4A22-B258-3FBAF662AA19} = {91C30620-70CA-46C7-AC71-71F3C602690E} {9FF51F3E-AF36-4F45-A797-C5F03A090298} = {91C30620-70CA-46C7-AC71-71F3C602690E} {8DB4158E-96EE-4DE5-A425-C9638F50B9ED} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} {9D1C3F29-1268-4241-BEFB-89D2859C62D3} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} {A6CC801B-CF30-4703-BC54-3E21F90B787D} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} {7264C8F6-73FB-4830-9306-1558D3EAC71B} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {0FB8F0FD-276C-413B-97A8-67ABE0C9043B} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {D3A99F36-4B72-4766-ABCD-CCEDC26DD139} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {2CD7408E-2F60-43C3-ACEB-C7D58CDD8462} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {EDA88BAB-9FA7-4A2D-8974-EFCFA24B3FEB} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {11D76FBC-DFAA-4B31-9DB0-206E171E3F94} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {8C42CA7C-1543-4F1B-A55F-28CD419C7D35} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {60206D22-E132-4695-8486-10BECA32C5CC} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {06877FED-15BA-421F-85C9-1A964FB97446} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {0056B0B6-CB3E-4F0E-B6DC-48D59CB8E235} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {5DB2E259-0D19-4A89-B8EC-B2912F39924D} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {0BFD78AA-FD94-4DB1-8495-8F5CC06D8F03} = {BFEDF709-A700-4769-9056-ACA934D828A8} {F5D850C9-D353-4B84-99BC-E336C231018C} = {BFEDF709-A700-4769-9056-ACA934D828A8} {59D7A9CD-9912-40E4-96E1-8A873F777F62} = {6D63CDF1-F62C-4614-AD8A-95B0A63AA070} {7337E34A-97B0-44FC-988B-7E6AE7E0FBBF} = {6D63CDF1-F62C-4614-AD8A-95B0A63AA070} {74D655D5-F661-4887-A1EB-5A6222AF5FCA} = {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} {1EB3DE5B-6357-498D-8CAC-EEC0209EA454} = {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} {79D37FFE-FF76-44B3-BB27-3DCAEFF2EBE9} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {BE18F227-A9F0-4B38-B689-4E2F9F09CA5F} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {17A4B817-68B1-4719-A9EF-BD8FAB747DE6} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {3ED56E55-84A6-422C-A8D4-A8439FB8F245} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {3799BA67-3C4F-4AE0-85DC-5BAAEA01A180} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {F5E2F6C4-19BA-497A-B754-232E469BE647} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {D93A2683-6D99-4F18-B378-91195D23E007} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {49A7CC5A-D5E7-4A07-917F-C6918B982BE8} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {5B2B9C0D-1B6D-4357-8307-6DE1EE0A41A3} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {BB248BAC-6E1B-433C-A254-75140A273AB5} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9} {C6E9D8C2-D5C1-441B-95ED-378E10DC5723} = {52157F12-CDE8-4092-A8F9-F9ECC5CBE0D1} EndGlobalSection EndGlobal pmdk-1.4.1/src/examples/Examples_debug.props000066400000000000000000000015661331545616200211040ustar00rootroot00000000000000 $(Platform)\$(Configuration)\$(TargetName)\ ex_$(RootNamespace)_$(ProjectName) Level3 Disabled true 4996 PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_MBCS;%(PreprocessorDefinitions) true true pmdk-1.4.1/src/examples/Examples_release.props000066400000000000000000000021061331545616200214250ustar00rootroot00000000000000 $(Platform)\$(Configuration)\$(TargetName)\ ex_$(RootNamespace)_$(ProjectName) Level3 MaxSpeed true 4996 true true PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_MBCS;%(PreprocessorDefinitions) true true true true pmdk-1.4.1/src/examples/Makefile000066400000000000000000000036471331545616200165350ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/Makefile -- build the Persistent Memory Development Kit examples # include ../common.inc DIRS = libpmem libpmemblk libpmemlog libpmemobj libvmem librpmem\ libpmempool libpmemcto ifeq ($(call cxx_ok), y) DIRS += libpmemobj++ else $(info NOTE: Skipping C++ examples because of compiler issues) endif include Makefile.inc rmtmp: $(RM) $(TMP_HEADERS) clobber clean: rmtmp pmdk-1.4.1/src/examples/Makefile.inc000066400000000000000000000112551331545616200172770ustar00rootroot00000000000000# # Copyright 2015-2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/Makefile.inc -- build the Persistent Memory Development Kit examples # TOP_SRC := $(dir $(lastword $(MAKEFILE_LIST))).. TOP := $(TOP_SRC)/.. HEADERS = $(wildcard *.h) $(wildcard *.hpp) INCDIR = $(TOP_SRC)/include LIBDIR = $(TOP_SRC)/debug include $(TOP)/src/common.inc CXXFLAGS = -std=c++11 -ggdb -Wall -Werror CXXFLAGS += $(GLIBC_CXXFLAGS) CXXFLAGS += $(EXTRA_CXXFLAGS) CFLAGS = -std=gnu99 -ggdb -Wall -Werror -Wmissing-prototypes $(EXTRA_CFLAGS) LDFLAGS = -Wl,-rpath=$(LIBDIR) -L$(LIBDIR) $(EXTRA_LDFLAGS) ifneq ($(SANITIZE),) CFLAGS += -fsanitize=$(SANITIZE) CXXFLAGS += -fsanitize=$(SANITIZE) LDFLAGS += -fsanitize=$(SANITIZE) endif INCS = -I$(INCDIR) -I. -I$(TOP_SRC)/examples $(OS_INCS) LIBS += $(OS_LIBS) $(LIBUUID) LINKER=$(CC) ifeq ($(COMPILE_LANG), cpp) LINKER=$(CXX) endif all-dirs: TARGET = all clean-dirs: TARGET = clean clobber-dirs: TARGET = clobber cstyle-dirs: TARGET = cstyle format-dirs: TARGET = format sparse-dirs: TARGET = sparse all: $(if $(DIRS), all-dirs) $(if $(LIBRARIES), all-libraries) $(if $(PROGS), all-progs) clean: $(if $(DIRS), clean-dirs) $(if $(PROGS), clean-progs) $(if $(LIBRARIES), clean-libraries) clobber: $(if $(DIRS), clobber-dirs) $(if $(PROGS), clobber-progs) $(if $(LIBRARIES), clobber-libraries) cstyle: $(if $(DIRS), cstyle-dirs) format: $(if $(DIRS), format-dirs) sparse: $(if $(DIRS), sparse-dirs) $(if $(DIRS), , $(sparse-c)) DYNAMIC_LIBRARIES = $(addprefix lib, $(addsuffix .so, $(LIBRARIES))) STATIC_LIBRARIES = $(addprefix lib, $(addsuffix .a, $(LIBRARIES))) all-dirs clean-dirs clobber-dirs cstyle-dirs format-dirs sparse-dirs: $(DIRS) all-progs: $(PROGS) all-libraries: $(DYNAMIC_LIBRARIES) $(STATIC_LIBRARIES) $(foreach l, $(LIBRARIES), $(eval lib$(l).so: lib$(l).o)) $(foreach l, $(LIBRARIES), $(eval lib$(l).a: lib$(l).o)) $(foreach l, $(LIBRARIES), $(eval lib$(l).o: CFLAGS+=-fPIC)) $(foreach l, $(LIBRARIES), $(eval lib$(l).o: CXXFLAGS+=-fPIC)) $(foreach l, $(LIBRARIES), $(eval $(l): lib$(l).so lib$(l).a)) $(foreach l, $(LIBRARIES), $(eval .PHONY: $(l))) $(DIRS): $(MAKE) -C $@ $(TARGET) clobber-progs: clean-progs clobber-libraries: clean-libraries clobber-progs clobber-libraries: ifneq ($(PROGS),) $(RM) $(PROGS) endif ifneq ($(LIBRARIES),) $(RM) $(DYNAMIC_LIBRARIES) $(STATIC_LIBRARIES) endif clean-progs clean-libraries: $(RM) *.o $(TMP_HEADERS) MAKEFILE_DEPS=Makefile $(TOP)/src/examples/Makefile.inc $(TOP)/src/common.inc ifneq ($(HEADERS),) ifneq ($(filter 1 2, $(CSTYLEON)),) TMP_HEADERS := $(addsuffix tmp, $(HEADERS)) endif endif all: $(TMP_HEADERS) %.o: %.c $(MAKEFILE_DEPS) $(call check-cstyle, $<) $(CC) -c -o $@ $(CFLAGS) $(INCS) $< %.o: %.cpp $(MAKEFILE_DEPS) $(call check-cstyle, $<) $(CXX) -c -o $@ $(CXXFLAGS) $(INCS) $< %.htmp: %.h $(call check-cstyle, $<, $@) %.hpptmp: %.hpp $(call check-cstyle, $<, $@) $(PROGS): | $(TMP_HEADERS) $(LINKER) -o $@ $^ $(LDFLAGS) $(LIBS) lib%.o: $(LD) -o $@ -r $^ $(STATIC_LIBRARIES): $(AR) rv $@ $< $(DYNAMIC_LIBRARIES): $(LINKER) -shared -o $@ $(LDFLAGS) -Wl,-shared,-soname=$@ $(LIBS) $< .PHONY: all clean clobber cstyle\ all-dirs clean-dirs clobber-dirs cstyle-dirs\ all-progs clean-progs clobber-progs cstyle-progs\ $(DIRS) pmdk-1.4.1/src/examples/README000066400000000000000000000035101331545616200157420ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/README. This directory contains brief educational examples illustrating the use of the PMDK libraries. For many of these examples, the Makefile rules are here just to check that the example compiles, loads against the appropriate library, and passes cstyle. If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. Developers new to PMDK are probably looking for libpmemobj. Many of the examples in this directory are described in more detail on the above web site. libpmem(7) -- low-level persistent memory support Example programs are in the libpmem directory. More documentation: http://pmem.io/pmdk/libpmem libpmemblk(7) -- pmem-resident arrays of blocks Example programs are in the libpmemblk directory. More documentation: http://pmem.io/pmdk/libpmemblk libpmemcto(7) -- close-to-open persistence Example programs are in the libpmemcto directory. More documentation: http://pmem.io/pmdk/libpmemcto libpmemlog(7) -- pmem-resident log files Example programs are in the libpmemlog directory. More documentation: http://pmem.io/pmdk/libpmemlog libpmemobj(7) -- transactional object store Example programs are in the libpmemobj directory. More documentation: http://pmem.io/pmdk/libpmemobj libpmempool(7) -- pool management, diagnostics and repair Example programs are in the libpmempool directory. More documentation: http://pmem.io/pmdk/libpmempool librpmem(7) -- remote access to persistent memory Example programs are in the libpmemcto directory. More documentation: http://pmem.io/pmdk/librpmem libvmem(7) -- volatile memory allocation library Example programs are in the libvmem directory. More documentation: http://pmem.io/pmdk/libvmem pmdk-1.4.1/src/examples/ex_common.h000066400000000000000000000052321331545616200172220ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * ex_common.h -- examples utilities */ #ifndef EX_COMMON_H #define EX_COMMON_H #include #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #ifdef __cplusplus extern "C" { #endif #ifndef _WIN32 #include #define CREATE_MODE_RW (S_IWUSR | S_IRUSR) /* * file_exists -- checks if file exists */ static inline int file_exists(char const *file) { return access(file, F_OK); } /* * find_last_set_64 -- returns last set bit position or -1 if set bit not found */ static inline int find_last_set_64(uint64_t val) { return 64 - __builtin_clzll(val) - 1; } #else #include #include #include #define CREATE_MODE_RW (S_IWRITE | S_IREAD) /* * file_exists -- checks if file exists */ static inline int file_exists(char const *file) { return _access(file, 0); } /* * find_last_set_64 -- returns last set bit position or -1 if set bit not found */ static inline int find_last_set_64(uint64_t val) { DWORD lz = 0; if (BitScanReverse64(&lz, val)) return (int)lz; else return -1; } #endif #ifdef __cplusplus } #endif #endif /* ex_common.h */ pmdk-1.4.1/src/examples/libpmem/000077500000000000000000000000001331545616200165105ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmem/.gitignore000066400000000000000000000000361331545616200204770ustar00rootroot00000000000000manpage simple_copy full_copy pmdk-1.4.1/src/examples/libpmem/Makefile000066400000000000000000000034001331545616200201450ustar00rootroot00000000000000# # Copyright 2014-2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmem/Makefile -- build the libpmem examples # PROGS = manpage simple_copy full_copy LIBS = -lpmem -pthread include ../Makefile.inc manpage: manpage.o simple_copy: simple_copy.o full_copy: full_copy.o pmdk-1.4.1/src/examples/libpmem/README000066400000000000000000000014021331545616200173650ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmem/README. This directory contains examples for libpmem, the library containing low-level persistent memory support. A detailed explanation of these examples can be found here: http://pmem.io/pmdk/libpmem manpage.c is the example used in the libpmem man page. simple_copy.c is a simple pmem_memcpy() example. full_copy.c shows how to use pmem_memcpy_nodrain(). To build these examples: make These examples can be built against an installed system using: make LIBDIR=/usr/lib INCDIR=/usr/include If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. Developers new to PMDK are probably looking for libpmemobj. pmdk-1.4.1/src/examples/libpmem/full_copy.c000066400000000000000000000074661331545616200206650ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * full_copy.c -- show how to use pmem_memcpy_nodrain() * * usage: full_copy src-file dst-file * * Copies src-file to dst-file in 4k chunks. */ #include #include #include #include #include #include #ifndef _WIN32 #include #else #include #endif #include #include /* copying 4k at a time to pmem for this example */ #define BUF_LEN 4096 /* * do_copy_to_pmem -- copy to pmem, postponing drain step until the end */ static void do_copy_to_pmem(char *pmemaddr, int srcfd, off_t len) { char buf[BUF_LEN]; int cc; /* copy the file, saving the last flush step to the end */ while ((cc = read(srcfd, buf, BUF_LEN)) > 0) { pmem_memcpy_nodrain(pmemaddr, buf, cc); pmemaddr += cc; } if (cc < 0) { perror("read"); exit(1); } /* perform final flush step */ pmem_drain(); } /* * do_copy_to_non_pmem -- copy to a non-pmem memory mapped file */ static void do_copy_to_non_pmem(char *addr, int srcfd, off_t len) { char *startaddr = addr; char buf[BUF_LEN]; int cc; /* copy the file, saving the last flush step to the end */ while ((cc = read(srcfd, buf, BUF_LEN)) > 0) { memcpy(addr, buf, cc); addr += cc; } if (cc < 0) { perror("read"); exit(1); } /* flush it */ if (pmem_msync(startaddr, len) < 0) { perror("pmem_msync"); exit(1); } } int main(int argc, char *argv[]) { int srcfd; struct stat stbuf; char *pmemaddr; size_t mapped_len; int is_pmem; if (argc != 3) { fprintf(stderr, "usage: %s src-file dst-file\n", argv[0]); exit(1); } /* open src-file */ if ((srcfd = open(argv[1], O_RDONLY)) < 0) { perror(argv[1]); exit(1); } /* find the size of the src-file */ if (fstat(srcfd, &stbuf) < 0) { perror("fstat"); exit(1); } /* create a pmem file and memory map it */ if ((pmemaddr = pmem_map_file(argv[2], stbuf.st_size, PMEM_FILE_CREATE|PMEM_FILE_EXCL, 0666, &mapped_len, &is_pmem)) == NULL) { perror("pmem_map_file"); exit(1); } /* determine if range is true pmem, call appropriate copy routine */ if (is_pmem) do_copy_to_pmem(pmemaddr, srcfd, stbuf.st_size); else do_copy_to_non_pmem(pmemaddr, srcfd, stbuf.st_size); close(srcfd); pmem_unmap(pmemaddr, mapped_len); exit(0); } pmdk-1.4.1/src/examples/libpmem/full_copy.vcxproj000066400000000000000000000045541331545616200221310ustar00rootroot00000000000000 Debug x64 Release x64 {0287C3DC-AE03-4714-AAFF-C52F062ECA6F} pmem 10.0.14393.0 Application true v140 Application false v140 $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmem/full_copy.vcxproj.filters000066400000000000000000000006461331545616200235760ustar00rootroot00000000000000 {0f7bab61-c1ad-4a74-8663-fe40f393b2eb} Source Files pmdk-1.4.1/src/examples/libpmem/manpage.c000066400000000000000000000051401331545616200202640ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * manpage.c -- simple example for the libpmem man page */ #include #include #include #include #include #include #ifndef _WIN32 #include #else #include #endif #include #include /* using 4k of pmem for this example */ #define PMEM_LEN 4096 #define PATH "/pmem-fs/myfile" int main(int argc, char *argv[]) { char *pmemaddr; size_t mapped_len; int is_pmem; /* create a pmem file and memory map it */ if ((pmemaddr = pmem_map_file(PATH, PMEM_LEN, PMEM_FILE_CREATE, 0666, &mapped_len, &is_pmem)) == NULL) { perror("pmem_map_file"); exit(1); } /* store a string to the persistent memory */ strcpy(pmemaddr, "hello, persistent memory"); /* flush above strcpy to persistence */ if (is_pmem) pmem_persist(pmemaddr, mapped_len); else pmem_msync(pmemaddr, mapped_len); /* * Delete the mappings. The region is also * automatically unmapped when the process is * terminated. */ pmem_unmap(pmemaddr, mapped_len); } pmdk-1.4.1/src/examples/libpmem/manpage.vcxproj000066400000000000000000000045541331545616200215450ustar00rootroot00000000000000 Debug x64 Release x64 {FCD0587A-4504-4F5E-8E9C-468CC03D250A} pmem 10.0.14393.0 Application true v140 Application false v140 $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmem/manpage.vcxproj.filters000066400000000000000000000007551331545616200232130ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx Source Files pmdk-1.4.1/src/examples/libpmem/simple_copy.c000066400000000000000000000056371331545616200212120ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * simple_copy.c -- show how to use pmem_memcpy_persist() * * usage: simple_copy src-file dst-file * * Reads 4k from src-file and writes it to dst-file. */ #include #include #include #include #include #include #ifndef _WIN32 #include #else #include #endif #include #include /* just copying 4k to pmem for this example */ #define BUF_LEN 4096 int main(int argc, char *argv[]) { int srcfd; char buf[BUF_LEN]; char *pmemaddr; size_t mapped_len; int is_pmem; int cc; if (argc != 3) { fprintf(stderr, "usage: %s src-file dst-file\n", argv[0]); exit(1); } /* open src-file */ if ((srcfd = open(argv[1], O_RDONLY)) < 0) { perror(argv[1]); exit(1); } /* create a pmem file and memory map it */ if ((pmemaddr = pmem_map_file(argv[2], BUF_LEN, PMEM_FILE_CREATE|PMEM_FILE_EXCL, 0666, &mapped_len, &is_pmem)) == NULL) { perror("pmem_map_file"); exit(1); } /* read up to BUF_LEN from srcfd */ if ((cc = read(srcfd, buf, BUF_LEN)) < 0) { pmem_unmap(pmemaddr, mapped_len); perror("read"); exit(1); } /* write it to the pmem */ if (is_pmem) { pmem_memcpy_persist(pmemaddr, buf, cc); } else { memcpy(pmemaddr, buf, cc); pmem_msync(pmemaddr, cc); } close(srcfd); pmem_unmap(pmemaddr, mapped_len); exit(0); } pmdk-1.4.1/src/examples/libpmem/simple_copy.vcxproj000066400000000000000000000045601331545616200224550ustar00rootroot00000000000000 Debug x64 Release x64 {D062166F-0EC7-4C13-A772-0C7157EEFE41} pmem 10.0.14393.0 Application true v140 Application false v140 $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmem/simple_copy.vcxproj.filters000066400000000000000000000006501331545616200241200ustar00rootroot00000000000000 {3bc86b19-55f2-4b90-9ccd-1470361ca84c} Source Files pmdk-1.4.1/src/examples/libpmemblk/000077500000000000000000000000001331545616200172015ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemblk/.gitignore000066400000000000000000000000101331545616200211600ustar00rootroot00000000000000manpage pmdk-1.4.1/src/examples/libpmemblk/Makefile000066400000000000000000000033241331545616200206430ustar00rootroot00000000000000# # Copyright 2014-2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemblk/Makefile -- build the libpmemblk examples # PROGS = manpage DIRS = assetdb LIBS = -lpmemblk -lpmem -pthread include ../Makefile.inc manpage: manpage.o pmdk-1.4.1/src/examples/libpmemblk/README000066400000000000000000000013331331545616200200610ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemblk/README. This directory contains examples for libpmemblk, the library providing pmem-resident arrays of blocks. Some of these examples are explained in more detail here: http://pmem.io/pmdk/libpmemblk manpage.c is the example used in the libpmemblk man page. assetdb contains a simple database built using libpmemblk. To build these examples: make These examples can be built against an installed system using: make LIBDIR=/usr/lib INCDIR=/usr/include If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. Developers new to PMDK are probably looking for libpmemobj. pmdk-1.4.1/src/examples/libpmemblk/assetdb/000077500000000000000000000000001331545616200206265ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemblk/assetdb/.gitignore000066400000000000000000000000631331545616200226150ustar00rootroot00000000000000asset_load asset_list asset_checkout asset_checkin pmdk-1.4.1/src/examples/libpmemblk/assetdb/Makefile000066400000000000000000000036361331545616200222760ustar00rootroot00000000000000# # Copyright 2014-2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemblk/assetdb/Makefile -- build the assetdb example # PROGS = asset_load asset_list asset_checkout asset_checkin LIBS = -lpmemblk -lpmem -pthread include ../../Makefile.inc asset_load: asset_load.o asset_list: asset_list.o asset_checkout: asset_checkout.o asset_checkin: asset_checkin.o asset_load.o asset_list.o asset_checkout.o asset_checkin.o: asset.h pmdk-1.4.1/src/examples/libpmemblk/assetdb/README000066400000000000000000000032731331545616200215130ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemblk/assetdb/README. This example illustrates how a very simple database can be built using the atomic arrays provided by libpmemblk. An array of records is created to track a list of assets (like books or computers, for example). Each asset is represented by a fixed-length record in the asset database. Since updates to a single record are atomic, the file remains consistent even if interrupted during an update. To run this example, follow these steps: 0. Build the example with "make". The libraries must be built first (i.e. by running "make" in ../../..). 1. Create the assetdb file. This can be anywhere but the point is it will be a much faster database file if it is created on a pmem-aware file system. For example, if /pmem is the mount point for a pmem-aware file system: $ fallocate -l 1G /pmem/assetdb 2. Load up the assets from a list of assets, which is just a simple text file containing asset description strings, one per line: $ asset_load /pmem/assetdb assetlist 3. Print the assets using: $ asset_list /pmem/assetdb 4. To mark an asset as checked out to someone: $ asset_checkout /pmem/assetdb asset-ID name The asset-ID is the ID printed by asset_list. The name may require quotes if it contains any whitespace or special characters. 5. To mark an asset as no longer checked out: $ asset_checkin /pmem/assetdb asset-ID As this is just an example to illustrate how pmemblk works, it may take some trial-and-error to find the best size for the assetdb -- the file must be large enough to hold about 512 bytes for each asset record, plus about 1% overhead used by libpmemblk to provide the atomicity. pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset.h000066400000000000000000000034271331545616200221240ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define ASSET_NAME_MAX 256 #define ASSET_USER_NAME_MAX 64 #define ASSET_CHECKED_OUT 2 #define ASSET_FREE 1 struct asset { char name[ASSET_NAME_MAX]; char user[ASSET_USER_NAME_MAX]; time_t time; int state; }; pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_checkin.c000066400000000000000000000054771331545616200236120ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * asset_checkin -- mark an asset as no longer checked out * * Usage: * asset_checkin /path/to/pm-aware/file asset-ID */ #include #include #include #include #include #include #include #include #include "asset.h" int main(int argc, char *argv[]) { PMEMblkpool *pbp; struct asset asset; int assetid; if (argc < 3) { fprintf(stderr, "usage: %s assetdb asset-ID\n", argv[0]); exit(1); } const char *path = argv[1]; assetid = atoi(argv[2]); assert(assetid > 0); /* open an array of atomically writable elements */ if ((pbp = pmemblk_open(path, sizeof(struct asset))) == NULL) { perror("pmemblk_open"); exit(1); } /* read a required element in */ if (pmemblk_read(pbp, &asset, assetid) < 0) { perror("pmemblk_read"); exit(1); } /* check if it contains any data */ if ((asset.state != ASSET_FREE) && (asset.state != ASSET_CHECKED_OUT)) { fprintf(stderr, "Asset ID %d not found\n", assetid); exit(1); } /* change state to free, clear user name and timestamp */ asset.state = ASSET_FREE; asset.user[0] = '\0'; asset.time = 0; if (pmemblk_write(pbp, &asset, assetid) < 0) { perror("pmemblk_write"); exit(1); } pmemblk_close(pbp); } pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_checkin.vcxproj000066400000000000000000000052601331545616200250510ustar00rootroot00000000000000 Debug x64 Release x64 {581B3A58-F3F0-4765-91E5-D0C82816A528} pmemblk 10.0.14393.0 {f7c6c6b6-4142-4c82-8699-4a9d8183181b} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_checkin.vcxproj.filters000066400000000000000000000014431331545616200265170ustar00rootroot00000000000000 {7b7d2f5a-464e-4d55-894b-3110e15303f1} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {c2e783a4-4f6d-419d-bbf6-1056eddfdd8f} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Header Files pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_checkout.c000066400000000000000000000061021331545616200237750ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * asset_checkout -- mark an asset as checked out to someone * * Usage: * asset_checkin /path/to/pm-aware/file asset-ID name */ #include #include #include #include #include #include #include #include #include "asset.h" int main(int argc, char *argv[]) { PMEMblkpool *pbp; struct asset asset; int assetid; if (argc < 4) { fprintf(stderr, "usage: %s assetdb asset-ID name\n", argv[0]); exit(1); } const char *path = argv[1]; assetid = atoi(argv[2]); assert(assetid > 0); /* open an array of atomically writable elements */ if ((pbp = pmemblk_open(path, sizeof(struct asset))) == NULL) { perror("pmemblk_open"); exit(1); } /* read a required element in */ if (pmemblk_read(pbp, &asset, assetid) < 0) { perror("pmemblk_read"); exit(1); } /* check if it contains any data */ if ((asset.state != ASSET_FREE) && (asset.state != ASSET_CHECKED_OUT)) { fprintf(stderr, "Asset ID %d not found", assetid); exit(1); } if (asset.state == ASSET_CHECKED_OUT) { fprintf(stderr, "Asset ID %d already checked out\n", assetid); exit(1); } /* update user name, set checked out state, and take timestamp */ strncpy(asset.user, argv[3], ASSET_USER_NAME_MAX - 1); asset.user[ASSET_USER_NAME_MAX - 1] = '\0'; asset.state = ASSET_CHECKED_OUT; time(&asset.time); /* put it back in the block */ if (pmemblk_write(pbp, &asset, assetid) < 0) { perror("pmemblk_write"); exit(1); } pmemblk_close(pbp); } pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_checkout.vcxproj000066400000000000000000000052621331545616200252540ustar00rootroot00000000000000 Debug x64 Release x64 {513C4CFA-BD5B-4470-BA93-F6D43778A754} pmemblk 10.0.14393.0 {f7c6c6b6-4142-4c82-8699-4a9d8183181b} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_checkout.vcxproj.filters000066400000000000000000000014441331545616200267210ustar00rootroot00000000000000 {7b7d2f5a-464e-4d55-894b-3110e15303f1} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {c2e783a4-4f6d-419d-bbf6-1056eddfdd8f} h;hh;hpp;hxx;hm;inl;inc;xsd Header Files Source Files pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_list.c000066400000000000000000000055531331545616200231540ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * asset_list -- list all assets in an assetdb file * * Usage: * asset_list /path/to/pm-aware/file */ #include #include #include #include #include #include #include #include "asset.h" int main(int argc, char *argv[]) { PMEMblkpool *pbp; int assetid; size_t nelements; struct asset asset; if (argc < 2) { fprintf(stderr, "usage: %s assetdb\n", argv[0]); exit(1); } const char *path = argv[1]; /* open an array of atomically writable elements */ if ((pbp = pmemblk_open(path, sizeof(struct asset))) == NULL) { perror(path); exit(1); } /* how many elements do we have? */ nelements = pmemblk_nblock(pbp); /* print out all the elements that contain assets data */ for (assetid = 0; assetid < nelements; ++assetid) { if (pmemblk_read(pbp, &asset, assetid) < 0) { perror("pmemblk_read"); exit(1); } if ((asset.state != ASSET_FREE) && (asset.state != ASSET_CHECKED_OUT)) { break; } printf("Asset ID: %d\n", assetid); if (asset.state == ASSET_FREE) printf(" State: Free\n"); else { printf(" State: Checked out\n"); printf(" User: %s\n", asset.user); printf(" Time: %s", ctime(&asset.time)); } printf(" Name: %s\n", asset.name); } pmemblk_close(pbp); } pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_list.vcxproj000066400000000000000000000052561331545616200244250ustar00rootroot00000000000000 Debug x64 Release x64 {8008010F-8718-4C5F-86B2-195AEBF73422} pmemblk 10.0.14393.0 {f7c6c6b6-4142-4c82-8699-4a9d8183181b} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_list.vcxproj.filters000066400000000000000000000014401331545616200260630ustar00rootroot00000000000000 {7b7d2f5a-464e-4d55-894b-3110e15303f1} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {c2e783a4-4f6d-419d-bbf6-1056eddfdd8f} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Header Files pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_load.c000066400000000000000000000066111331545616200231140ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * asset_load -- given pre-allocated assetdb file, load it up with assets * * Usage: * fallocate -l 1G /path/to/pm-aware/file * asset_load /path/to/pm-aware/file asset-file * * The asset-file should contain the names of the assets, one per line. */ #include #include #include #include #include #include #include #include #include "asset.h" int main(int argc, char *argv[]) { FILE *fp; int len = ASSET_NAME_MAX; PMEMblkpool *pbp; int assetid = 0; size_t nelements; char *line; if (argc < 3) { fprintf(stderr, "usage: %s assetdb assetlist\n", argv[0]); exit(1); } const char *path_pool = argv[1]; const char *path_list = argv[2]; /* create pmemblk pool in existing (but as yet unmodified) file */ pbp = pmemblk_create(path_pool, sizeof(struct asset), 0, CREATE_MODE_RW); if (pbp == NULL) { perror(path_pool); exit(1); } nelements = pmemblk_nblock(pbp); if ((fp = fopen(path_list, "r")) == NULL) { perror(path_list); exit(1); } /* * Read in all the assets from the assetfile and put them in the * array, if a name of the asset is longer than ASSET_NAME_SIZE_MAX, * truncate it. */ line = malloc(len); if (line == NULL) { perror("malloc"); exit(1); } while (fgets(line, len, fp) != NULL) { struct asset asset; if (assetid >= nelements) { fprintf(stderr, "%s: too many assets to fit in %s " "(only %d assets loaded)\n", path_list, path_pool, assetid); exit(1); } memset(&asset, '\0', sizeof(asset)); asset.state = ASSET_FREE; strncpy(asset.name, line, ASSET_NAME_MAX - 1); asset.name[ASSET_NAME_MAX - 1] = '\0'; if (pmemblk_write(pbp, &asset, assetid) < 0) { perror("pmemblk_write"); exit(1); } assetid++; } free(line); fclose(fp); pmemblk_close(pbp); } pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_load.vcxproj000066400000000000000000000052561331545616200243710ustar00rootroot00000000000000 Debug x64 Release x64 {C7E42AE1-052F-4024-B8BA-DE5DCE6BBEEC} pmemblk 10.0.14393.0 {f7c6c6b6-4142-4c82-8699-4a9d8183181b} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemblk/assetdb/asset_load.vcxproj.filters000066400000000000000000000014401331545616200260270ustar00rootroot00000000000000 {7b7d2f5a-464e-4d55-894b-3110e15303f1} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {c2e783a4-4f6d-419d-bbf6-1056eddfdd8f} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Header Files pmdk-1.4.1/src/examples/libpmemblk/manpage.c000066400000000000000000000055561331545616200207700ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * manpage.c -- simple example for the libpmemblk man page */ #include #include #include #include #ifndef _WIN32 #include #endif #include #include /* size of the pmemblk pool -- 1 GB */ #define POOL_SIZE ((size_t)(1 << 30)) /* size of each element in the pmem pool */ #define ELEMENT_SIZE 1024 int main(int argc, char *argv[]) { const char path[] = "/pmem-fs/myfile"; PMEMblkpool *pbp; size_t nelements; char buf[ELEMENT_SIZE]; /* create the pmemblk pool or open it if it already exists */ pbp = pmemblk_create(path, ELEMENT_SIZE, POOL_SIZE, 0666); if (pbp == NULL) pbp = pmemblk_open(path, ELEMENT_SIZE); if (pbp == NULL) { perror(path); exit(1); } /* how many elements fit into the file? */ nelements = pmemblk_nblock(pbp); printf("file holds %zu elements\n", nelements); /* store a block at index 5 */ strcpy(buf, "hello, world"); if (pmemblk_write(pbp, buf, 5) < 0) { perror("pmemblk_write"); exit(1); } /* read the block at index 10 (reads as zeros initially) */ if (pmemblk_read(pbp, buf, 10) < 0) { perror("pmemblk_read"); exit(1); } /* zero out the block at index 5 */ if (pmemblk_set_zero(pbp, 5) < 0) { perror("pmemblk_set_zero"); exit(1); } /* ... */ pmemblk_close(pbp); } pmdk-1.4.1/src/examples/libpmemblk/manpage.vcxproj000066400000000000000000000051111331545616200222240ustar00rootroot00000000000000 Debug x64 Release x64 {8010BBB0-C71B-4EFF-95EB-65C01E5EC197} pmemblk 10.0.14393.0 Application true v140 Application false v140 true $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest {f7c6c6b6-4142-4c82-8699-4a9d8183181b} {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmemblk/manpage.vcxproj.filters000066400000000000000000000012541331545616200236770ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files pmdk-1.4.1/src/examples/libpmemcto/000077500000000000000000000000001331545616200172165ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemcto/.gitignore000066400000000000000000000000101331545616200211750ustar00rootroot00000000000000manpage pmdk-1.4.1/src/examples/libpmemcto/Makefile000066400000000000000000000033311331545616200206560ustar00rootroot00000000000000# # Copyright 2017-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemcto/Makefile -- build the libpmemcto examples # PROGS = manpage DIRS = life libart LIBS = -lpmemcto -lpmem -pthread include ../Makefile.inc manpage: manpage.o pmdk-1.4.1/src/examples/libpmemcto/README000066400000000000000000000015131331545616200200760ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemcto/README. This directory contains examples for libpmemcto. Some of these examples are explained in more detail here: http://pmem.io/pmdk/libpmemcto manpage.c is the example used in the libpmemcto man page. lifesave contains a simple screen saver which implements Conway's Game of Life built using libpmemcto (Windows-only). life contains a simple example which implements Conway's Game of Life built using libpmemcto (Linux-only). To build these examples: make These examples can be built against an installed system using: make LIBDIR=/usr/lib INCDIR=/usr/include If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. Developers new to PMDK are probably looking for libpmemobj. pmdk-1.4.1/src/examples/libpmemcto/libart/000077500000000000000000000000001331545616200204735ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemcto/libart/.gitignore000066400000000000000000000000101331545616200224520ustar00rootroot00000000000000arttree pmdk-1.4.1/src/examples/libpmemcto/libart/Makefile000066400000000000000000000045601331545616200221400ustar00rootroot00000000000000# # Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH # Copyright 2016-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # ========================================================================== # # Filename: Makefile # # Description: implement ART tree using libvmem based on libart # # Author: Andreas Bluemle, Dieter Kasper # Andreas.Bluemle.external@ts.fujitsu.com # dieter.kasper@ts.fujitsu.com # # Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH # ========================================================================== # include ../../../common.inc ARCH := $(call get_arch) ifeq ($(ARCH), x86_64) # libart uses x86 intrinsics PROGS = arttree LIBRARIES = art endif LIBS = -lpmem -lpmemcto include ../../Makefile.inc CFLAGS += -ggdb -O0 $(PROGS): | $(DYNAMIC_LIBRARIES) $(PROGS): LDFLAGS += -Wl,-rpath=. -L. -lart libart.o: art.o arttree: arttree.o pmdk-1.4.1/src/examples/libpmemcto/libart/art.c000066400000000000000000000675241331545616200214430ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2012, Armon Dadgar. All rights reserved. * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * ========================================================================== * * Filename: art.c * * Description: implement ART tree using libpmemcto based on libart * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * ========================================================================== */ /* * based on https://github.com/armon/libart/src/art.c */ #include #include #include #include #include #include #include "libpmemcto.h" #include "art.h" /* * Macros to manipulate pointer tags */ #define IS_LEAF(x) (((uintptr_t)x & 1)) #define SET_LEAF(x) ((void *)((uintptr_t)x | 1)) #define LEAF_RAW(x) ((void *)((uintptr_t)x & ~1)) /* * Allocates a node of the given type, * initializes to zero and sets the type. */ static art_node * alloc_node(PMEMctopool *pcp, uint8_t type) { art_node *n; switch (type) { case NODE4: n = pmemcto_calloc(pcp, 1, sizeof(art_node4)); break; case NODE16: n = pmemcto_calloc(pcp, 1, sizeof(art_node16)); break; case NODE48: n = pmemcto_calloc(pcp, 1, sizeof(art_node48)); break; case NODE256: n = pmemcto_calloc(pcp, 1, sizeof(art_node256)); break; default: abort(); } assert(n != NULL); n->type = type; return n; } /* * Initializes an ART tree * @return 0 on success. */ int art_tree_init(art_tree *t) { t->root = NULL; t->size = 0; return 0; } /* * Recursively destroys the tree */ static void destroy_node(PMEMctopool *pcp, art_node *n) { // Break if null if (!n) return; // Special case leafs if (IS_LEAF(n)) { pmemcto_free(pcp, LEAF_RAW(n)); return; } // Handle each node type int i; union { art_node4 *p1; art_node16 *p2; art_node48 *p3; art_node256 *p4; } p; switch (n->type) { case NODE4: p.p1 = (art_node4 *)n; for (i = 0; i < n->num_children; i++) { destroy_node(pcp, p.p1->children[i]); } break; case NODE16: p.p2 = (art_node16 *)n; for (i = 0; i < n->num_children; i++) { destroy_node(pcp, p.p2->children[i]); } break; case NODE48: p.p3 = (art_node48 *)n; for (i = 0; i < n->num_children; i++) { destroy_node(pcp, p.p3->children[i]); } break; case NODE256: p.p4 = (art_node256 *)n; for (i = 0; i < 256; i++) { if (p.p4->children[i]) destroy_node(pcp, p.p4->children[i]); } break; default: abort(); } // Free ourself on the way up pmemcto_free(pcp, n); } /* * Destroys an ART tree * @return 0 on success. */ int art_tree_destroy(PMEMctopool *pcp, art_tree *t) { destroy_node(pcp, t->root); return 0; } /* * Returns the size of the ART tree. */ static art_node ** find_child(art_node *n, unsigned char c) { __m128i cmp; int i, mask, bitfield; union { art_node4 *p1; art_node16 *p2; art_node48 *p3; art_node256 *p4; } p; switch (n->type) { case NODE4: p.p1 = (art_node4 *)n; for (i = 0; i < n->num_children; i++) { if (p.p1->keys[i] == c) return &p.p1->children[i]; } break; case NODE16: p.p2 = (art_node16 *)n; // Compare the key to all 16 stored keys cmp = _mm_cmpeq_epi8(_mm_set1_epi8(c), _mm_loadu_si128((__m128i *)p.p2->keys)); // Use a mask to ignore children that don't exist mask = (1 << n->num_children) - 1; bitfield = _mm_movemask_epi8(cmp) & mask; /* * If we have a match (any bit set) then we can * return the pointer match using ctz to get * the index. */ if (bitfield) return &p.p2->children[__builtin_ctz(bitfield)]; break; case NODE48: p.p3 = (art_node48 *)n; i = p.p3->keys[c]; if (i) return &p.p3->children[i - 1]; break; case NODE256: p.p4 = (art_node256 *)n; if (p.p4->children[c]) return &p.p4->children[c]; break; default: abort(); } return NULL; } // Simple inlined if static inline int min(int a, int b) { return (a < b) ? a : b; } /* * Returns the number of prefix characters shared between * the key and node. */ static int check_prefix(const art_node *n, const unsigned char *key, int key_len, int depth) { int max_cmp = min(min(n->partial_len, MAX_PREFIX_LEN), key_len - depth); int idx; for (idx = 0; idx < max_cmp; idx++) { if (n->partial[idx] != key[depth + idx]) return idx; } return idx; } /* * Checks if a leaf matches * @return 0 on success. */ static int leaf_matches(const art_leaf *n, const unsigned char *key, int key_len, int depth) { (void) depth; // Fail if the key lengths are different if (n->key_len != (uint32_t)key_len) return 1; // Compare the keys starting at the depth return memcmp(n->key, key, key_len); } /* * Searches for a value in the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @return NULL if the item was not found, otherwise * the value pointer is returned. */ void * art_search(const art_tree *t, const unsigned char *key, int key_len) { art_node **child; art_node *n = t->root; int prefix_len, depth = 0; while (n) { // Might be a leaf if (IS_LEAF(n)) { n = LEAF_RAW(n); // Check if the expanded path matches if (!leaf_matches((art_leaf *)n, key, key_len, depth)) { return ((art_leaf *)n)->value; } return NULL; } // Bail if the prefix does not match if (n->partial_len) { prefix_len = check_prefix(n, key, key_len, depth); if (prefix_len != min(MAX_PREFIX_LEN, n->partial_len)) return NULL; depth = depth + n->partial_len; } // Recursively search child = find_child(n, key[depth]); n = (child) ? *child : NULL; depth++; } return NULL; } // Find the minimum leaf under a node static art_leaf * minimum(const art_node *n) { // Handle base cases if (!n) return NULL; if (IS_LEAF(n)) return LEAF_RAW(n); int idx; switch (n->type) { case NODE4: return minimum(((art_node4 *)n)->children[0]); case NODE16: return minimum(((art_node16 *)n)->children[0]); case NODE48: idx = 0; while (!((art_node48 *)n)->keys[idx]) idx++; idx = ((art_node48 *)n)->keys[idx] - 1; assert(idx < 48); return minimum(((art_node48 *) n)->children[idx]); case NODE256: idx = 0; while (!((art_node256 *)n)->children[idx]) idx++; return minimum(((art_node256 *)n)->children[idx]); default: abort(); } } // Find the maximum leaf under a node static art_leaf * maximum(const art_node *n) { // Handle base cases if (!n) return NULL; if (IS_LEAF(n)) return LEAF_RAW(n); int idx; switch (n->type) { case NODE4: return maximum( ((art_node4 *)n)->children[n->num_children - 1]); case NODE16: return maximum( ((art_node16 *)n)->children[n->num_children - 1]); case NODE48: idx = 255; while (!((art_node48 *)n)->keys[idx]) idx--; idx = ((art_node48 *)n)->keys[idx] - 1; assert((idx >= 0) && (idx < 48)); return maximum(((art_node48 *)n)->children[idx]); case NODE256: idx = 255; while (!((art_node256 *)n)->children[idx]) idx--; return maximum(((art_node256 *)n)->children[idx]); default: abort(); } } /* * Returns the minimum valued leaf */ art_leaf * art_minimum(art_tree *t) { return minimum((art_node *)t->root); } /* * Returns the maximum valued leaf */ art_leaf * art_maximum(art_tree *t) { return maximum((art_node *) t->root); } static art_leaf * make_leaf(PMEMctopool *pcp, const unsigned char *key, int key_len, void *value, int val_len) { art_leaf *l = pmemcto_malloc(pcp, sizeof(art_leaf) + key_len + val_len); assert(l != NULL); l->key_len = key_len; l->val_len = val_len; l->key = &(l->data[0]) + 0; l->value = &(l->data[0]) + key_len; memcpy(l->key, key, key_len); memcpy(l->value, value, val_len); return l; } static int longest_common_prefix(art_leaf *l1, art_leaf *l2, int depth) { int max_cmp = min(l1->key_len, l2->key_len) - depth; int idx; for (idx = 0; idx < max_cmp; idx++) { if (l1->key[depth + idx] != l2->key[depth + idx]) return idx; } return idx; } static void copy_header(art_node *dest, art_node *src) { dest->num_children = src->num_children; dest->partial_len = src->partial_len; memcpy(dest->partial, src->partial, min(MAX_PREFIX_LEN, src->partial_len)); } static void add_child256(PMEMctopool *pcp, art_node256 *n, art_node **ref, unsigned char c, void *child) { (void) ref; n->n.num_children++; n->children[c] = child; } static void add_child48(PMEMctopool *pcp, art_node48 *n, art_node **ref, unsigned char c, void *child) { if (n->n.num_children < 48) { int pos = 0; while (n->children[pos]) pos++; n->children[pos] = child; n->keys[c] = pos + 1; n->n.num_children++; } else { art_node256 *new = (art_node256 *)alloc_node(pcp, NODE256); for (int i = 0; i < 256; i++) { if (n->keys[i]) { new->children[i] = n->children[n->keys[i] - 1]; } } copy_header((art_node *)new, (art_node *)n); *ref = (art_node *)new; pmemcto_free(pcp, n); add_child256(pcp, new, ref, c, child); } } static void add_child16(PMEMctopool *pcp, art_node16 *n, art_node **ref, unsigned char c, void *child) { if (n->n.num_children < 16) { __m128i cmp; // Compare the key to all 16 stored keys cmp = _mm_cmplt_epi8(_mm_set1_epi8(c), _mm_loadu_si128((__m128i *)n->keys)); // Use a mask to ignore children that don't exist unsigned mask = (1 << n->n.num_children) - 1; unsigned bitfield = _mm_movemask_epi8(cmp) & mask; // Check if less than any unsigned idx; if (bitfield) { idx = __builtin_ctz(bitfield); memmove(n->keys + idx + 1, n->keys + idx, n->n.num_children - idx); memmove(n->children + idx + 1, n->children + idx, (n->n.num_children - idx) * sizeof(void *)); } else idx = n->n.num_children; // Set the child n->keys[idx] = c; n->children[idx] = child; n->n.num_children++; } else { art_node48 *new = (art_node48 *)alloc_node(pcp, NODE48); // Copy the child pointers and populate the key map memcpy(new->children, n->children, sizeof(void *) * n->n.num_children); for (int i = 0; i < n->n.num_children; i++) { new->keys[n->keys[i]] = i + 1; } copy_header((art_node *)new, (art_node *)n); *ref = (art_node *) new; pmemcto_free(pcp, n); add_child48(pcp, new, ref, c, child); } } static void add_child4(PMEMctopool *pcp, art_node4 *n, art_node **ref, unsigned char c, void *child) { if (n->n.num_children < 4) { int idx; for (idx = 0; idx < n->n.num_children; idx++) { if (c < n->keys[idx]) break; } // Shift to make room memmove(n->keys + idx + 1, n->keys + idx, n->n.num_children - idx); memmove(n->children + idx + 1, n->children + idx, (n->n.num_children - idx) * sizeof(void *)); // Insert element n->keys[idx] = c; n->children[idx] = child; n->n.num_children++; } else { art_node16 *new = (art_node16 *)alloc_node(pcp, NODE16); // Copy the child pointers and the key map memcpy(new->children, n->children, sizeof(void *) * n->n.num_children); memcpy(new->keys, n->keys, sizeof(unsigned char) * n->n.num_children); copy_header((art_node *)new, (art_node *)n); *ref = (art_node *)new; pmemcto_free(pcp, n); add_child16(pcp, new, ref, c, child); } } static void add_child(PMEMctopool *pcp, art_node *n, art_node **ref, unsigned char c, void *child) { switch (n->type) { case NODE4: return add_child4(pcp, (art_node4 *)n, ref, c, child); case NODE16: return add_child16(pcp, (art_node16 *)n, ref, c, child); case NODE48: return add_child48(pcp, (art_node48 *)n, ref, c, child); case NODE256: return add_child256(pcp, (art_node256 *)n, ref, c, child); default: abort(); } } /* * Calculates the index at which the prefixes mismatch */ static int prefix_mismatch(const art_node *n, const unsigned char *key, int key_len, int depth) { int max_cmp = min(min(MAX_PREFIX_LEN, n->partial_len), key_len - depth); int idx; for (idx = 0; idx < max_cmp; idx++) { if (n->partial[idx] != key[depth + idx]) return idx; } // If the prefix is short we can avoid finding a leaf if (n->partial_len > MAX_PREFIX_LEN) { // Prefix is longer than what we've checked, find a leaf art_leaf *l = minimum(n); assert(l != NULL); max_cmp = min(l->key_len, key_len) - depth; for (; idx < max_cmp; idx++) { if (l->key[idx + depth] != key[depth + idx]) return idx; } } return idx; } static void * recursive_insert(PMEMctopool *pcp, art_node *n, art_node **ref, const unsigned char *key, int key_len, void *value, int val_len, int depth, int *old) { // If we are at a NULL node, inject a leaf if (!n) { *ref = (art_node *)SET_LEAF( make_leaf(pcp, key, key_len, value, val_len)); return NULL; } // If we are at a leaf, we need to replace it with a node if (IS_LEAF(n)) { art_leaf *l = LEAF_RAW(n); // Check if we are updating an existing value if (!leaf_matches(l, key, key_len, depth)) { *old = 1; void *old_val = l->value; l->value = value; return old_val; } // New value, we must split the leaf into a node4 art_node4 *new = (art_node4 *)alloc_node(pcp, NODE4); // Create a new leaf art_leaf *l2 = make_leaf(pcp, key, key_len, value, val_len); // Determine longest prefix int longest_prefix = longest_common_prefix(l, l2, depth); new->n.partial_len = longest_prefix; memcpy(new->n.partial, key + depth, min(MAX_PREFIX_LEN, longest_prefix)); // Add the leafs to the new node4 *ref = (art_node *)new; add_child4(pcp, new, ref, l->key[depth + longest_prefix], SET_LEAF(l)); add_child4(pcp, new, ref, l2->key[depth + longest_prefix], SET_LEAF(l2)); return NULL; } // Check if given node has a prefix if (n->partial_len) { // Determine if the prefixes differ, since we need to split int prefix_diff = prefix_mismatch(n, key, key_len, depth); if ((uint32_t)prefix_diff >= n->partial_len) { depth += n->partial_len; goto RECURSE_SEARCH; } // Create a new node art_node4 *new = (art_node4 *)alloc_node(pcp, NODE4); *ref = (art_node *)new; new->n.partial_len = prefix_diff; memcpy(new->n.partial, n->partial, min(MAX_PREFIX_LEN, prefix_diff)); // Adjust the prefix of the old node if (n->partial_len <= MAX_PREFIX_LEN) { add_child4(pcp, new, ref, n->partial[prefix_diff], n); n->partial_len -= (prefix_diff + 1); memmove(n->partial, n->partial + prefix_diff + 1, min(MAX_PREFIX_LEN, n->partial_len)); } else { n->partial_len -= (prefix_diff + 1); art_leaf *l = minimum(n); assert(l != NULL); add_child4(pcp, new, ref, l->key[depth + prefix_diff], n); memcpy(n->partial, l->key + depth + prefix_diff + 1, min(MAX_PREFIX_LEN, n->partial_len)); } // Insert the new leaf art_leaf *l = make_leaf(pcp, key, key_len, value, val_len); add_child4(pcp, new, ref, key[depth + prefix_diff], SET_LEAF(l)); return NULL; } RECURSE_SEARCH:; // Find a child to recurse to art_node **child = find_child(n, key[depth]); if (child) { return recursive_insert(pcp, *child, child, key, key_len, value, val_len, depth + 1, old); } // No child, node goes within us art_leaf *l = make_leaf(pcp, key, key_len, value, val_len); add_child(pcp, n, ref, key[depth], SET_LEAF(l)); return NULL; } /* * Inserts a new value into the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @arg value Opaque value. * @return NULL if the item was newly inserted, otherwise * the old value pointer is returned. */ void * art_insert(PMEMctopool *pcp, art_tree *t, const unsigned char *key, int key_len, void *value, int val_len) { int old_val = 0; void *old = recursive_insert(pcp, t->root, &t->root, key, key_len, value, val_len, 0, &old_val); if (!old_val) t->size++; return old; } static void remove_child256(PMEMctopool *pcp, art_node256 *n, art_node **ref, unsigned char c) { n->children[c] = NULL; n->n.num_children--; // Resize to a node48 on underflow, not immediately to prevent // trashing if we sit on the 48/49 boundary if (n->n.num_children == 37) { art_node48 *new = (art_node48 *)alloc_node(pcp, NODE48); *ref = (art_node *) new; copy_header((art_node *)new, (art_node *)n); int pos = 0; for (int i = 0; i < 256; i++) { if (n->children[i]) { assert(pos < 48); new->children[pos] = n->children[i]; new->keys[i] = pos + 1; pos++; } } pmemcto_free(pcp, n); } } static void remove_child48(PMEMctopool *pcp, art_node48 *n, art_node **ref, unsigned char c) { int pos = n->keys[c]; n->keys[c] = 0; n->children[pos - 1] = NULL; n->n.num_children--; if (n->n.num_children == 12) { art_node16 *new = (art_node16 *)alloc_node(pcp, NODE16); *ref = (art_node *)new; copy_header((art_node *) new, (art_node *)n); int child = 0; for (int i = 0; i < 256; i++) { pos = n->keys[i]; if (pos) { assert(child < 16); new->keys[child] = i; new->children[child] = n->children[pos - 1]; child++; } } pmemcto_free(pcp, n); } } static void remove_child16(PMEMctopool *pcp, art_node16 *n, art_node **ref, art_node **l) { int pos = l - n->children; memmove(n->keys + pos, n->keys + pos + 1, n->n.num_children - 1 - pos); memmove(n->children + pos, n->children + pos + 1, (n->n.num_children - 1 - pos) * sizeof(void *)); n->n.num_children--; if (n->n.num_children == 3) { art_node4 *new = (art_node4 *)alloc_node(pcp, NODE4); *ref = (art_node *) new; copy_header((art_node *)new, (art_node *)n); memcpy(new->keys, n->keys, 4); memcpy(new->children, n->children, 4 * sizeof(void *)); pmemcto_free(pcp, n); } } static void remove_child4(PMEMctopool *pcp, art_node4 *n, art_node **ref, art_node **l) { int pos = l - n->children; memmove(n->keys + pos, n->keys + pos + 1, n->n.num_children - 1 - pos); memmove(n->children + pos, n->children + pos + 1, (n->n.num_children - 1 - pos) * sizeof(void *)); n->n.num_children--; // Remove nodes with only a single child if (n->n.num_children == 1) { art_node *child = n->children[0]; if (!IS_LEAF(child)) { // Concatenate the prefixes int prefix = n->n.partial_len; if (prefix < MAX_PREFIX_LEN) { n->n.partial[prefix] = n->keys[0]; prefix++; } if (prefix < MAX_PREFIX_LEN) { int sub_prefix = min(child->partial_len, MAX_PREFIX_LEN - prefix); memcpy(n->n.partial + prefix, child->partial, sub_prefix); prefix += sub_prefix; } // Store the prefix in the child memcpy(child->partial, n->n.partial, min(prefix, MAX_PREFIX_LEN)); child->partial_len += n->n.partial_len + 1; } *ref = child; pmemcto_free(pcp, n); } } static void remove_child(PMEMctopool *pcp, art_node *n, art_node **ref, unsigned char c, art_node **l) { switch (n->type) { case NODE4: return remove_child4(pcp, (art_node4 *)n, ref, l); case NODE16: return remove_child16(pcp, (art_node16 *)n, ref, l); case NODE48: return remove_child48(pcp, (art_node48 *)n, ref, c); case NODE256: return remove_child256(pcp, (art_node256 *)n, ref, c); default: abort(); } } static art_leaf * recursive_delete(PMEMctopool *pcp, art_node *n, art_node **ref, const unsigned char *key, int key_len, int depth) { // Search terminated if (!n) return NULL; // Handle hitting a leaf node if (IS_LEAF(n)) { art_leaf *l = LEAF_RAW(n); if (!leaf_matches(l, key, key_len, depth)) { *ref = NULL; return l; } return NULL; } // Bail if the prefix does not match if (n->partial_len) { int prefix_len = check_prefix(n, key, key_len, depth); if (prefix_len != min(MAX_PREFIX_LEN, n->partial_len)) { return NULL; } depth = depth + n->partial_len; } // Find child node art_node **child = find_child(n, key[depth]); if (!child) return NULL; // If the child is leaf, delete from this node if (IS_LEAF(*child)) { art_leaf *l = LEAF_RAW(*child); if (!leaf_matches(l, key, key_len, depth)) { remove_child(pcp, n, ref, key[depth], child); return l; } return NULL; // Recurse } else { return recursive_delete(pcp, *child, child, key, key_len, depth + 1); } } /* * Deletes a value from the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @return NULL if the item was not found, otherwise * the value pointer is returned. */ void * art_delete(PMEMctopool *pcp, art_tree *t, const unsigned char *key, int key_len) { art_leaf *l = recursive_delete(pcp, t->root, &t->root, key, key_len, 0); if (l) { t->size--; void *old = l->value; pmemcto_free(pcp, l); return old; } return NULL; } // Recursively iterates over the tree static int recursive_iter(art_node *n, art_callback cb, void *data) { // Handle base cases if (!n) return 0; if (IS_LEAF(n)) { art_leaf *l = LEAF_RAW(n); return cb(data, (const unsigned char *)l->key, l->key_len, l->value, l->val_len); } int idx, res; switch (n->type) { case NODE4: for (int i = 0; i < n->num_children; i++) { res = recursive_iter(((art_node4 *)n)->children[i], cb, data); if (res) return res; } break; case NODE16: for (int i = 0; i < n->num_children; i++) { res = recursive_iter( ((art_node16 *)n)->children[i], cb, data); if (res) return res; } break; case NODE48: for (int i = 0; i < 256; i++) { idx = ((art_node48 *)n)->keys[i]; if (!idx) continue; res = recursive_iter( ((art_node48 *)n)->children[idx - 1], cb, data); if (res) return res; } break; case NODE256: for (int i = 0; i < 256; i++) { if (!((art_node256 *)n)->children[i]) continue; res = recursive_iter( ((art_node256 *)n)->children[i], cb, data); if (res) return res; } break; default: abort(); } return 0; } /* * Iterates through the entries pairs in the map, * invoking a callback for each. The call back gets a * key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter(art_tree *t, art_callback cb, void *data) { return recursive_iter(t->root, cb, data); } // Recursively iterates over the tree static int recursive_iter2(art_node *n, art_callback cb, void *data) { cb_data _cbd, *cbd = &_cbd; int first = 1; // Handle base cases if (!n) return 0; cbd->node = (void *)n; cbd->node_type = n->type; cbd->child_idx = -1; if (IS_LEAF(n)) { art_leaf *l = LEAF_RAW(n); return cb(cbd, (const unsigned char *)l->key, l->key_len, l->value, l->val_len); } int idx, res; switch (n->type) { case NODE4: for (int i = 0; i < n->num_children; i++) { cbd->first_child = first; first = 0; cbd->child_idx = i; cb((void *)cbd, NULL, 0, NULL, 0); res = recursive_iter2(((art_node4 *)n)->children[i], cb, data); if (res) return res; } break; case NODE16: for (int i = 0; i < n->num_children; i++) { cbd->first_child = first; first = 0; cbd->child_idx = i; cb((void *)cbd, NULL, 0, NULL, 0); res = recursive_iter2(((art_node16 *)n)->children[i], cb, data); if (res) return res; } break; case NODE48: for (int i = 0; i < 256; i++) { idx = ((art_node48 *)n)->keys[i]; if (!idx) continue; cbd->first_child = first; first = 0; cbd->child_idx = i; cb((void *)cbd, NULL, 0, NULL, 0); res = recursive_iter2( ((art_node48 *)n)->children[idx - 1], cb, data); if (res) return res; } break; case NODE256: for (int i = 0; i < 256; i++) { if (!((art_node256 *)n)->children[i]) continue; cbd->first_child = first; first = 0; cbd->child_idx = i; cb((void *)cbd, NULL, 0, NULL, 0); res = recursive_iter2( ((art_node256 *)n)->children[i], cb, data); if (res) return res; } break; default: abort(); } return 0; } /* * Iterates through the entries pairs in the map, * invoking a callback for each. The call back gets a * key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter2(art_tree *t, art_callback cb, void *data) { return recursive_iter2(t->root, cb, data); } /* * Checks if a leaf prefix matches * @return 0 on success. */ static int leaf_prefix_matches(const art_leaf *n, const unsigned char *prefix, int prefix_len) { // Fail if the key length is too short if (n->key_len < (uint32_t)prefix_len) return 1; // Compare the keys return memcmp(n->key, prefix, prefix_len); } /* * Iterates through the entries pairs in the map, * invoking a callback for each that matches a given prefix. * The call back gets a key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg prefix The prefix of keys to read * @arg prefix_len The length of the prefix * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter_prefix(art_tree *t, const unsigned char *key, int key_len, art_callback cb, void *data) { art_node **child; art_node *n = t->root; int prefix_len, depth = 0; while (n) { // Might be a leaf if (IS_LEAF(n)) { n = LEAF_RAW(n); // Check if the expanded path matches if (!leaf_prefix_matches( (art_leaf *)n, key, key_len)) { art_leaf *l = (art_leaf *)n; return cb(data, (const unsigned char *)l->key, l->key_len, l->value, l->val_len); } return 0; } // If the depth matches the prefix, we need to handle this node if (depth == key_len) { art_leaf *l = minimum(n); assert(l != NULL); if (!leaf_prefix_matches(l, key, key_len)) return recursive_iter(n, cb, data); return 0; } // Bail if the prefix does not match if (n->partial_len) { prefix_len = prefix_mismatch(n, key, key_len, depth); // If there is no match, search is terminated if (!prefix_len) return 0; // If we've matched the prefix, iterate on this node else if (depth + prefix_len == key_len) { return recursive_iter(n, cb, data); } // if there is a full match, go deeper depth = depth + n->partial_len; } // Recursively search child = find_child(n, key[depth]); n = (child) ? *child : NULL; depth++; } return 0; } pmdk-1.4.1/src/examples/libpmemcto/libart/art.h000066400000000000000000000155131331545616200214370ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2012, Armon Dadgar. All rights reserved. * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * ========================================================================== * * Filename: art.h * * Description: implement ART tree using libpmemcto based on libart * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * ========================================================================== */ /* * based on https://github.com/armon/libart/src/art.h */ #include #ifndef ART_H #define ART_H #ifdef __cplusplus extern "C" { #endif #define NODE4 1 #define NODE16 2 #define NODE48 3 #define NODE256 4 #define MAX_PREFIX_LEN 10 #if defined(__GNUC__) && !defined(__clang__) #if __STDC_VERSION__ >= 199901L && 402 == (__GNUC__ * 100 + __GNUC_MINOR__) /* * GCC 4.2.2's C99 inline keyword support is pretty broken; avoid. Introduced in * GCC 4.2.something, fixed in 4.3.0. So checking for specific major.minor of * 4.2 is fine. */ #define BROKEN_GCC_C99_INLINE #endif #endif typedef int(*art_callback)(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *value, uint32_t val_len); /* * This struct is included as part * of all the various node sizes */ typedef struct { uint8_t type; uint8_t num_children; uint32_t partial_len; unsigned char partial[MAX_PREFIX_LEN]; } art_node; /* * Small node with only 4 children */ typedef struct { art_node n; unsigned char keys[4]; art_node *children[4]; } art_node4; /* * Node with 16 children */ typedef struct { art_node n; unsigned char keys[16]; art_node *children[16]; } art_node16; /* * Node with 48 children, but * a full 256 byte field. */ typedef struct { art_node n; unsigned char keys[256]; art_node *children[48]; } art_node48; /* * Full node with 256 children */ typedef struct { art_node n; art_node *children[256]; } art_node256; /* * Represents a leaf. These are * of arbitrary size, as they include the key. */ typedef struct { uint32_t key_len; uint32_t val_len; unsigned char *key; unsigned char *value; unsigned char data[]; } art_leaf; /* * Main struct, points to root. */ typedef struct { art_node *root; uint64_t size; } art_tree; /* * Initializes an ART tree * @return 0 on success. */ int art_tree_init(art_tree *t); /* * DEPRECATED * Initializes an ART tree * @return 0 on success. */ #define init_art_tree(...) art_tree_init(__VA_ARGS__) /* * Destroys an ART tree * @return 0 on success. */ int art_tree_destroy(PMEMctopool *pcp, art_tree *t); /* * Returns the size of the ART tree. */ #ifdef BROKEN_GCC_C99_INLINE #define art_size(t) ((t)->size) #else static inline uint64_t art_size(art_tree *t) { return t->size; } #endif /* * Inserts a new value into the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @arg value Opaque value. * @return NULL if the item was newly inserted, otherwise * the old value pointer is returned. */ void *art_insert(PMEMctopool *pcp, art_tree *t, const unsigned char *key, int key_len, void *value, int val_len); /* * Deletes a value from the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @return NULL if the item was not found, otherwise * the value pointer is returned. */ void *art_delete(PMEMctopool *pcp, art_tree *t, const unsigned char *key, int key_len); /* * Searches for a value in the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @return NULL if the item was not found, otherwise * the value pointer is returned. */ void *art_search(const art_tree *t, const unsigned char *key, int key_len); /* * Returns the minimum valued leaf * @return The minimum leaf or NULL */ art_leaf *art_minimum(art_tree *t); /* * Returns the maximum valued leaf * @return The maximum leaf or NULL */ art_leaf *art_maximum(art_tree *t); /* * Iterates through the entries pairs in the map, * invoking a callback for each. The call back gets a * key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter(art_tree *t, art_callback cb, void *data); typedef struct _cb_data { int node_type; int child_idx; int first_child; void *node; } cb_data; int art_iter2(art_tree *t, art_callback cb, void *data); /* * Iterates through the entries pairs in the map, * invoking a callback for each that matches a given prefix. * The call back gets a key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg prefix The prefix of keys to read * @arg prefix_len The length of the prefix * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter_prefix(art_tree *t, const unsigned char *prefix, int prefix_len, art_callback cb, void *data); #ifdef __cplusplus } #endif #endif pmdk-1.4.1/src/examples/libpmemcto/libart/arttree.c000066400000000000000000000765131331545616200223210ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree.c * * Description: implement ART tree using libpmemcto based on libart * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #define _WITH_GETLINE #endif #include #include #include #include #include #include #include #include #include "libpmemcto.h" #include "arttree.h" #define APPNAME "arttree" #define SRCVERSION "0.1" struct str2int_map { char *name; int value; }; #define ART_NODE 0 #define ART_NODE4 1 #define ART_NODE16 2 #define ART_NODE48 3 #define ART_NODE256 4 #define ART_TREE_ROOT 5 #define ART_LEAF 6 struct str2int_map art_node_types[] = { {"art_node", ART_NODE}, {"art_node4", ART_NODE4}, {"art_node16", ART_NODE16}, {"art_node48", ART_NODE48}, {"art_node256", ART_NODE256}, {"art_tree", ART_TREE_ROOT}, {"art_leaf", ART_LEAF}, {NULL, -1} }; struct datastore { void *priv; }; /* * context - main context of datastore */ struct ds_context { char *filename; /* name of pool file */ int mode; /* operation mode */ int insertions; /* number of insert operations to perform */ int newpool; /* complete new memory pool */ size_t psize; /* size of pool */ PMEMctopool *pcp; /* handle to pmemcto pool */ art_tree *art_tree; /* art_tree root */ bool fileio; unsigned fmode; FILE *input; FILE *output; uint64_t address; unsigned char *key; int type; int fd; /* file descriptor for file io mode */ }; #define FILL (1 << 1) #define INTERACTIVE (1 << 3) struct ds_context my_context; #define read_key(c, p) read_line(c, p) #define read_value(c, p) read_line(c, p) static void usage(char *progname); int initialize_context(struct ds_context *ctx, int ac, char *av[]); int add_elements(struct ds_context *ctx); ssize_t read_line(struct ds_context *ctx, unsigned char **line); void exit_handler(struct ds_context *ctx); int art_tree_map_init(struct datastore *ds, struct ds_context *ctx); void pmemobj_ds_set_priv(struct datastore *ds, void *priv); static int dump_art_leaf_callback(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len); static int dump_art_tree_graph(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len); static void print_node_info(char *nodetype, uint64_t addr, art_node *an); static void print_help(char *appname); static void print_version(char *appname); static struct command *get_command(char *cmd_str); static int help_func(char *appname, struct ds_context *ctx, int argc, char *argv[]); static void help_help(char *appname); static int quit_func(char *appname, struct ds_context *ctx, int argc, char *argv[]); static void quit_help(char *appname); static int set_output_func(char *appname, struct ds_context *ctx, int argc, char *argv[]); static void set_output_help(char *appname); static int arttree_fill_func(char *appname, struct ds_context *ctx, int ac, char *av[]); static void arttree_fill_help(char *appname); static int arttree_examine_func(char *appname, struct ds_context *ctx, int ac, char *av[]); static void arttree_examine_help(char *appname); static int arttree_search_func(char *appname, struct ds_context *ctx, int ac, char *av[]); static void arttree_search_help(char *appname); static int arttree_delete_func(char *appname, struct ds_context *ctx, int ac, char *av[]); static void arttree_delete_help(char *appname); static int arttree_dump_func(char *appname, struct ds_context *ctx, int ac, char *av[]); static void arttree_dump_help(char *appname); static int arttree_graph_func(char *appname, struct ds_context *ctx, int ac, char *av[]); static void arttree_graph_help(char *appname); static int map_lookup(struct str2int_map *map, char *name); static void arttree_examine(struct ds_context *ctx, void *addr, int node_type); static void dump_art_tree_root(struct ds_context *ctx, art_tree *node); static void dump_art_node(struct ds_context *ctx, art_node *node); static void dump_art_node4(struct ds_context *ctx, art_node4 *node); static void dump_art_node16(struct ds_context *ctx, art_node16 *node); static void dump_art_node48(struct ds_context *ctx, art_node48 *node); static void dump_art_node256(struct ds_context *ctx, art_node256 *node); static void dump_art_leaf(struct ds_context *ctx, art_leaf *node); static char *asciidump(unsigned char *s, int32_t len); void outv_err(const char *fmt, ...); void outv_err_vargs(const char *fmt, va_list ap); /* * command -- struct for commands definition */ struct command { const char *name; const char *brief; int (*func)(char *, struct ds_context *, int, char *[]); void (*help)(char *); }; struct command commands[] = { { .name = "fill", .brief = "create and fill an art tree", .func = arttree_fill_func, .help = arttree_fill_help, }, { .name = "dump", .brief = "dump an art tree", .func = arttree_dump_func, .help = arttree_dump_help, }, { .name = "graph", .brief = "dump an art tree for graphical conversion", .func = arttree_graph_func, .help = arttree_graph_help, }, { .name = "help", .brief = "print help text about a command", .func = help_func, .help = help_help, }, { .name = "examine", .brief = "examine art tree structures", .func = arttree_examine_func, .help = arttree_examine_help, }, { .name = "search", .brief = "search for key in art tree", .func = arttree_search_func, .help = arttree_search_help, }, { .name = "delete", .brief = "delete leaf with key from art tree", .func = arttree_delete_func, .help = arttree_delete_help, }, { .name = "set_output", .brief = "set output file", .func = set_output_func, .help = set_output_help, }, { .name = "quit", .brief = "quit arttree structure examiner", .func = quit_func, .help = quit_help, }, }; /* * number of arttree_structures commands */ #define COMMANDS_NUMBER (sizeof(commands) / sizeof(commands[0])) int initialize_context(struct ds_context *ctx, int ac, char *av[]) { int errors = 0; int opt; char mode; if ((ctx == NULL) || (ac < 2)) { errors++; } if (!errors) { ctx->filename = NULL; ctx->psize = PMEMCTO_MIN_POOL; ctx->newpool = 0; ctx->pcp = NULL; ctx->art_tree = NULL; ctx->fileio = false; ctx->fmode = 0666; ctx->mode = 0; ctx->input = stdin; ctx->output = stdout; ctx->fd = -1; } if (!errors) { while ((opt = getopt(ac, av, "m:n:s:")) != -1) { switch (opt) { case 'm': mode = optarg[0]; if (mode == 'f') { ctx->mode |= FILL; } else if (mode == 'i') { ctx->mode |= INTERACTIVE; } else { errors++; } break; case 'n': { long insertions; insertions = strtol(optarg, NULL, 0); if (insertions > 0 && insertions < LONG_MAX) { ctx->insertions = insertions; } break; } default: errors++; break; } } } if (optind >= ac) { errors++; } if (!errors) { ctx->filename = strdup(av[optind]); } return errors; } void exit_handler(struct ds_context *ctx) { if (!ctx->fileio) { if (ctx->pcp) { pmemcto_close(ctx->pcp); } } else { if (ctx->fd > - 1) { close(ctx->fd); } } } int art_tree_map_init(struct datastore *ds, struct ds_context *ctx) { int errors = 0; char *error_string; /* calculate a required pool size */ if (ctx->psize < PMEMCTO_MIN_POOL) ctx->psize = PMEMCTO_MIN_POOL; if (access(ctx->filename, F_OK) != 0) { error_string = "pmemcto_create"; ctx->pcp = pmemcto_create(ctx->filename, "arttree_cto", ctx->psize, ctx->fmode); ctx->newpool = 1; } else { error_string = "pmemcto_open"; ctx->pcp = pmemcto_open(ctx->filename, "arttree_cto"); } if (ctx->pcp == NULL) { perror(error_string); errors++; } return errors; } /* * pmemobj_ds_set_priv -- set private structure of datastore */ void pmemobj_ds_set_priv(struct datastore *ds, void *priv) { ds->priv = priv; } struct datastore myds; static void usage(char *progname) { printf("usage: %s -m [f|d|g] filename\n", progname); printf(" -m mode known modes are\n"); printf(" f fill create and fill art tree\n"); printf(" i interactive interact with art tree\n"); printf(" -n insertions number of key-value pairs to insert " "into the tree\n"); printf(" -s size size of the pmemcto pool file " "[minimum: PMEMCTO_MIN_POOL=%ld]\n", PMEMCTO_MIN_POOL); printf("\nfilling an art tree is done by reading key value pairs\n" "from standard input.\n" "Both keys and values are single line only.\n"); } /* * print_version -- prints arttree version message */ static void print_version(char *appname) { printf("%s %s\n", appname, SRCVERSION); } /* * print_help -- prints arttree help message */ static void print_help(char *appname) { usage(appname); print_version(appname); printf("\n"); printf("Options:\n"); printf(" -h, --help display this help and exit\n"); printf("\n"); printf("The available commands are:\n"); int i; for (i = 0; i < COMMANDS_NUMBER; i++) printf("%s\t- %s\n", commands[i].name, commands[i].brief); printf("\n"); } static int map_lookup(struct str2int_map *map, char *name) { int idx; int value = -1; for (idx = 0; ; idx++) { if (map[idx].name == NULL) { break; } if (strcmp((const char *)map[idx].name, (const char *)name) == 0) { value = map[idx].value; break; } } return value; } /* * get_command -- returns command for specified command name */ static struct command * get_command(char *cmd_str) { int i; if (cmd_str == NULL) { return NULL; } for (i = 0; i < COMMANDS_NUMBER; i++) { if (strcmp(cmd_str, commands[i].name) == 0) return &commands[i]; } return NULL; } /* * quit_help -- prints help message for quit command */ static void quit_help(char *appname) { printf("Usage: quit\n"); printf(" terminate interactive arttree function\n"); } /* * quit_func -- quit arttree function */ static int quit_func(char *appname, struct ds_context *ctx, int argc, char *argv[]) { printf("\n"); pmemcto_set_root_pointer(ctx->pcp, ctx->art_tree); pmemcto_close(ctx->pcp); exit(0); return 0; } static void set_output_help(char *appname) { printf("set_output output redirection\n"); printf("Usage: set_output []\n"); printf(" redirect subsequent output to specified file\n"); printf(" if file_name is not specified, " "then reset to standard output\n"); } static int set_output_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { int errors = 0; if (ac == 1) { if ((ctx->output != NULL) && (ctx->output != stdout)) { (void) fclose(ctx->output); } ctx->output = stdout; } else if (ac == 2) { FILE *out_fp; out_fp = fopen(av[1], "w+"); if (out_fp == (FILE *)NULL) { outv_err("set_output: cannot open %s for writing\n", av[1]); errors++; } else { if ((ctx->output != NULL) && (ctx->output != stdout)) { (void) fclose(ctx->output); } ctx->output = out_fp; } } else { outv_err("set_output: too many arguments [%d]\n", ac); errors++; } return errors; } /* * help_help -- prints help message for help command */ static void help_help(char *appname) { printf("Usage: %s help \n", appname); } /* * help_func -- prints help message for specified command */ static int help_func(char *appname, struct ds_context *ctx, int argc, char *argv[]) { if (argc > 1) { char *cmd_str = argv[1]; struct command *cmdp = get_command(cmd_str); if (cmdp && cmdp->help) { cmdp->help(appname); return 0; } else { outv_err("No help text for '%s' command\n", cmd_str); return -1; } } else { print_help(appname); return -1; } } static int arttree_fill_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { int errors = 0; int opt; (void) appname; RESET_GETOPT; while ((opt = getopt(ac, av, "n:")) != -1) { switch (opt) { case 'n': { long insertions; insertions = strtol(optarg, NULL, 0); if (insertions > 0 && insertions < LONG_MAX) { ctx->insertions = insertions; } break; } default: errors++; break; } } if (optind >= ac) { outv_err("fill: missing input filename\n"); arttree_fill_help(appname); errors++; } if (!errors) { struct stat statbuf; FILE *in_fp; if (stat(av[optind], &statbuf)) { outv_err("fill: cannot stat %s\n", av[optind]); errors++; } else { in_fp = fopen(av[optind], "r"); if (in_fp == (FILE *)NULL) { outv_err("fill: cannot open %s for reading\n", av[optind]); errors++; } else { if ((ctx->input != NULL) && (ctx->input != stdin)) { (void) fclose(ctx->input); } ctx->input = in_fp; } } } if (!errors) { if (add_elements(ctx)) { perror("add elements"); errors++; } if ((ctx->input != NULL) && (ctx->input != stdin)) { (void) fclose(ctx->input); } ctx->input = stdin; } return errors; } static void arttree_fill_help(char *appname) { (void) appname; printf("create and fill an art tree\n"); printf("Usage: fill [-n ] \n"); printf(" number of key-val pairs to fill " "the art tree\n"); printf(" input file for key-val pairs\n"); } static char outbuf[1024]; static char * asciidump(unsigned char *s, int32_t len) { char *p; int l; p = outbuf; if ((s != 0) && (len > 0)) { while (len--) { if (isprint((*s)&0xff)) { l = sprintf(p, "%c", (*s)&0xff); } else { l = sprintf(p, "\\%.2x", (*s)&0xff); } p += l; s++; } } *p = '\0'; p++; return outbuf; } static void dump_art_tree_root(struct ds_context *ctx, art_tree *node) { fprintf(ctx->output, "art_tree 0x%" PRIxPTR " {\n" " size=%" PRId64 ";\n root=0x%" PRIxPTR ";\n}\n", (uintptr_t)node, node->size, (uintptr_t)(node->root)); } static void dump_art_node(struct ds_context *ctx, art_node *node) { fprintf(ctx->output, "art_node 0x%" PRIxPTR " {\n" " type=%s;\n" " num_children=%d;\n" " partial_len=%d;\n" " partial=[%s];\n" "}\n", (uintptr_t)node, art_node_types[node->type].name, node->num_children, node->partial_len, asciidump(node->partial, node->partial_len)); } static void dump_art_node4(struct ds_context *ctx, art_node4 *node) { int i; fprintf(ctx->output, "art_node4 0x%" PRIxPTR " {\n", (uintptr_t)node); dump_art_node(ctx, &(node->n)); for (i = 0; i < node->n.num_children; i++) { fprintf(ctx->output, " key[%d]=%s;\n", i, asciidump(&(node->keys[i]), 1)); fprintf(ctx->output, " child[%d]=0x%" PRIxPTR ";\n", i, (uintptr_t)(node->children[i])); } fprintf(ctx->output, "}\n"); } static void dump_art_node16(struct ds_context *ctx, art_node16 *node) { int i; fprintf(ctx->output, "art_node16 0x%" PRIxPTR " {\n", (uintptr_t)node); dump_art_node(ctx, &(node->n)); for (i = 0; i < node->n.num_children; i++) { fprintf(ctx->output, " key[%d]=%s;\n", i, asciidump(&(node->keys[i]), 1)); fprintf(ctx->output, " child[%d]=0x%" PRIxPTR ";\n", i, (uintptr_t)(node->children[i])); } fprintf(ctx->output, "}\n"); } static void dump_art_node48(struct ds_context *ctx, art_node48 *node) { int i; int idx; fprintf(ctx->output, "art_node48 0x%" PRIxPTR " {\n", (uintptr_t)node); dump_art_node(ctx, &(node->n)); for (i = 0; i < 256; i++) { idx = node->keys[i]; if (!idx) continue; fprintf(ctx->output, " key[%d]=%s;\n", i, asciidump((unsigned char *)(&i), 1)); fprintf(ctx->output, " child[%d]=0x%" PRIxPTR ";\n", idx, (uintptr_t)(node->children[idx])); } fprintf(ctx->output, "}\n"); } static void dump_art_node256(struct ds_context *ctx, art_node256 *node) { int i; fprintf(ctx->output, "art_node48 0x%" PRIxPTR " {\n", (uintptr_t)node); dump_art_node(ctx, &(node->n)); for (i = 0; i < 256; i++) { if (node->children[i] == NULL) continue; fprintf(ctx->output, " key[%i]=%s;\n", i, asciidump((unsigned char *)(&i), 1)); fprintf(ctx->output, " child[%d]=0x%" PRIxPTR ";\n", i, (uintptr_t)(node->children[i])); } fprintf(ctx->output, "}\n"); } static void dump_art_leaf(struct ds_context *ctx, art_leaf *node) { fprintf(ctx->output, "art_leaf 0x%" PRIxPTR " {\n" " key_len=%u;\n" " key=[%s];\n", (uintptr_t)node, node->key_len, asciidump(node->key, (int32_t)node->key_len)); fprintf(ctx->output, " val_len=%u;\n" " value=[%s];\n" "}\n", node->val_len, asciidump(node->value, (int32_t)node->val_len)); } static void arttree_examine(struct ds_context *ctx, void *addr, int node_type) { if (addr == NULL) return; switch (node_type) { case ART_TREE_ROOT: dump_art_tree_root(ctx, (art_tree *)addr); break; case ART_NODE: dump_art_node(ctx, (art_node *)addr); break; case ART_NODE4: dump_art_node4(ctx, (art_node4 *)addr); break; case ART_NODE16: dump_art_node16(ctx, (art_node16 *)addr); break; case ART_NODE48: dump_art_node48(ctx, (art_node48 *)addr); break; case ART_NODE256: dump_art_node256(ctx, (art_node256 *)addr); break; case ART_LEAF: dump_art_leaf(ctx, (art_leaf *)addr); break; default: break; } fflush(ctx->output); } static int arttree_examine_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { int errors = 0; (void) appname; if (ac > 1) { if (ac < 3) { outv_err("examine: missing argument\n"); arttree_examine_help(appname); errors++; } else { ctx->address = (uint64_t)strtol(av[1], NULL, 0); ctx->type = map_lookup(&(art_node_types[0]), av[2]); } } else { ctx->address = (uint64_t)ctx->art_tree; ctx->type = ART_TREE_ROOT; } if (!errors) { if (ctx->output == NULL) ctx->output = stdout; arttree_examine(ctx, (void *)(ctx->address), ctx->type); } return errors; } static void arttree_examine_help(char *appname) { (void) appname; printf("examine structures of an art tree\n"); printf("Usage: examine
\n"); printf("
address of art tree structure to examine\n"); printf(" input file for key-val pairs\n"); printf("Known types are\n art_tree\n art_node\n" " art_node4\n art_node16\n art_node48\n art_node256\n" " art_leaf\n"); printf("If invoked without arguments, then the root of the art tree" " is dumped\n"); } static int arttree_search_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { void *p; int errors = 0; (void) appname; if (ac > 1) { ctx->key = (unsigned char *)strdup(av[1]); assert(ctx->key != NULL); } else { outv_err("search: missing key\n"); arttree_search_help(appname); errors++; } if (!errors) { if (ctx->output == NULL) ctx->output = stdout; p = art_search(ctx->art_tree, ctx->key, (int)strlen((const char *)ctx->key)); if (p != NULL) { fprintf(ctx->output, "found key [%s]: ", asciidump(ctx->key, strlen((const char *)ctx->key))); fprintf(ctx->output, "value [%s]\n", asciidump((unsigned char *)p, 20)); } else { fprintf(ctx->output, "not found key [%s]\n", asciidump(ctx->key, strlen((const char *)ctx->key))); } } return errors; } static void arttree_search_help(char *appname) { (void) appname; printf("search for key in art tree\n"); printf("Usage: search \n"); printf(" the key to search for\n"); } static int arttree_delete_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { void *p; int errors = 0; (void) appname; if (ac > 1) { ctx->key = (unsigned char *)strdup(av[1]); assert(ctx->key != NULL); } else { outv_err("delete: missing key\n"); arttree_delete_help(appname); errors++; } if (!errors) { if (ctx->output == NULL) ctx->output = stdout; p = art_delete(ctx->pcp, ctx->art_tree, ctx->key, (int)strlen((const char *)ctx->key)); if (p != NULL) { fprintf(ctx->output, "delete leaf with key [%s]:", asciidump(ctx->key, strlen((const char *)ctx->key))); fprintf(ctx->output, " value [%s]\n", asciidump((unsigned char *)p, 20)); } else { fprintf(ctx->output, "no leaf with key [%s]\n", asciidump(ctx->key, strlen((const char *)ctx->key))); } } return errors; } static void arttree_delete_help(char *appname) { (void) appname; printf("delete leaf with key from art tree\n"); printf("Usage: delete \n"); printf(" the key of the leaf to delete\n"); } static int arttree_dump_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { (void) appname; (void) ac; (void) av; art_iter(ctx->art_tree, dump_art_leaf_callback, NULL); return 0; } static void arttree_dump_help(char *appname) { (void) appname; printf("dump all leafs of an art tree\n"); printf("Usage: dump\n"); printf("\nThis function uses the art_iter() interface to descend\n"); printf("to all leafs of the art tree\n"); } static int arttree_graph_func(char *appname, struct ds_context *ctx, int ac, char *av[]) { (void) appname; (void) ac; (void) av; fprintf(ctx->output, "digraph g {\nrankdir=LR;\n"); art_iter2(ctx->art_tree, dump_art_tree_graph, NULL); fprintf(ctx->output, "}\n"); return 0; } static void arttree_graph_help(char *appname) { (void) appname; printf("dump art tree for graphical output (graphiviz/dot)\n"); printf("Usage: graph\n"); printf("\nThis function uses the art_iter2() interface to descend\n"); printf("through the art tree and produces output for graphviz/dot\n"); } int main(int argc, char *argv[]) { if (initialize_context(&my_context, argc, argv) != 0) { usage(argv[0]); return 1; } if (art_tree_map_init(&myds, &my_context) != 0) { fprintf(stderr, "failed to initialize memory pool file\n"); return 1; } if (my_context.pcp == NULL) { perror("pool initialization"); return 1; } my_context.art_tree = (art_tree *)pmemcto_get_root_pointer(my_context.pcp); if (my_context.art_tree == NULL) { my_context.art_tree = pmemcto_malloc(my_context.pcp, sizeof(art_tree)); assert(my_context.art_tree != NULL); if (art_tree_init(my_context.art_tree)) { perror("art tree setup"); return 1; } } if ((my_context.mode & INTERACTIVE)) { char *line; ssize_t read; size_t len; char *args[20]; int nargs; struct command *cmdp; /* interactive mode: read commands and execute them */ line = NULL; printf("\n> "); while ((read = getline(&line, &len, stdin)) != -1) { if (line[read - 1] == '\n') { line[read - 1] = '\0'; } args[0] = strtok(line, " "); cmdp = get_command(args[0]); if (cmdp == NULL) { printf("[%s]: command not supported\n", args[0] ? args[0] : "NULL"); printf("\n> "); continue; } nargs = 1; while (1) { args[nargs] = strtok(NULL, " "); if (args[nargs] == NULL) { break; } nargs++; } (void) cmdp->func(APPNAME, &my_context, nargs, args); printf("\n> "); } if (line != NULL) { free(line); } } if ((my_context.mode & FILL)) { if (add_elements(&my_context)) { perror("add elements"); return 1; } } exit_handler(&my_context); return 0; } int add_elements(struct ds_context *ctx) { int errors = 0; int i; int key_len; int val_len; unsigned char *key; unsigned char *value; if (ctx == NULL) { errors++; } else if (ctx->pcp == NULL) { errors++; } if (!errors) { for (i = 0; i < ctx->insertions; i++) { key = NULL; value = NULL; key_len = read_key(ctx, &key); val_len = read_value(ctx, &value); art_insert(ctx->pcp, ctx->art_tree, key, key_len, value, val_len); if (key != NULL) free(key); if (value != NULL) free(value); } } return errors; } ssize_t read_line(struct ds_context *ctx, unsigned char **line) { size_t len = -1; ssize_t read = -1; *line = NULL; if ((read = getline((char **)line, &len, ctx->input)) > 0) { (*line)[read - 1] = '\0'; } return read - 1; } static int dump_art_leaf_callback(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len) { fprintf(my_context.output, "key len %d = [%s], ", key_len, asciidump((unsigned char *)key, key_len)); fprintf(my_context.output, "value len %d = [%s]\n", val_len, asciidump((unsigned char *)val, val_len)); fflush(my_context.output); return 0; } /* * Macros to manipulate pointer tags */ #define IS_LEAF(x) (((uintptr_t)x & 1)) #define SET_LEAF(x) ((void *)((uintptr_t)x | 1)) #define LEAF_RAW(x) ((void *)((uintptr_t)x & ~1)) unsigned char hexvals[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; static void print_node_info(char *nodetype, uint64_t addr, art_node *an) { int p_len; p_len = an->partial_len; fprintf(my_context.output, "N%" PRIx64 " [label=\"%s at\\n0x%" PRIx64 "\\n%d children", addr, nodetype, addr, an->num_children); if (p_len != 0) { fprintf(my_context.output, "\\nlen %d", p_len); fprintf(my_context.output, ": "); asciidump(an->partial, p_len); } fprintf(my_context.output, "\"];\n"); } static int dump_art_tree_graph(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len) { cb_data *cbd; art_node4 *an4; art_node16 *an16; art_node48 *an48; art_node256 *an256; art_leaf *al; void *child; int idx; if (data == NULL) return 0; cbd = (cb_data *)data; if (IS_LEAF(cbd->node)) { al = LEAF_RAW(cbd->node); fprintf(my_context.output, "N%" PRIxPTR " [shape=box, " "label=\"leaf at\\n0x%" PRIxPTR "\"];\n", (uintptr_t)al, (uintptr_t)al); fprintf(my_context.output, "N%" PRIxPTR " [shape=box, " "label=\"key at 0x%" PRIxPTR ": %s\"];\n", (uintptr_t)al->key, (uintptr_t)al->key, asciidump(al->key, al->key_len)); fprintf(my_context.output, "N%" PRIxPTR " [shape=box, " "label=\"value at 0x%" PRIxPTR ": %s\"];\n", (uintptr_t)al->value, (uintptr_t)al->value, asciidump(al->value, al->val_len)); fprintf(my_context.output, "N%" PRIxPTR " -> N%" PRIxPTR ";\n", (uintptr_t)al, (uintptr_t)al->key); fprintf(my_context.output, "N%" PRIxPTR " -> N%" PRIxPTR ";\n", (uintptr_t)al, (uintptr_t)al->value); return 0; } switch (cbd->node_type) { case NODE4: an4 = (art_node4 *)cbd->node; child = (void *)(an4->children[cbd->child_idx]); child = LEAF_RAW(child); if (child != NULL) { if (cbd->first_child) print_node_info("node4", (uint64_t)(cbd->node), &(an4->n)); fprintf(my_context.output, "N%" PRIxPTR " -> N%" PRIxPTR " [label=\"%s\"];\n", (uintptr_t)an4, (uintptr_t)child, asciidump(&(an4->keys[cbd->child_idx]), 1)); } break; case NODE16: an16 = (art_node16 *)cbd->node; child = (void *)(an16->children[cbd->child_idx]); child = LEAF_RAW(child); if (child != NULL) { if (cbd->first_child) print_node_info("node16", (uint64_t)(cbd->node), &(an16->n)); fprintf(my_context.output, "N%" PRIxPTR " -> N%" PRIxPTR " [label=\"%s\"];\n", (uintptr_t)an16, (uintptr_t)child, asciidump(&(an16->keys[cbd->child_idx]), 1)); } break; case NODE48: an48 = (art_node48 *)cbd->node; idx = an48->keys[cbd->child_idx]; child = (void *) (an48->children[idx - 1]); child = LEAF_RAW(child); if (child != NULL) { if (cbd->first_child) print_node_info("node48", (uint64_t)(cbd->node), &(an48->n)); fprintf(my_context.output, "N%" PRIxPTR " -> N%" PRIxPTR " [label=\"%s\"];\n", (uintptr_t)an48, (uintptr_t)child, asciidump(&(hexvals[cbd->child_idx]), 1)); } break; case NODE256: an256 = (art_node256 *)cbd->node; child = (void *)(an256->children[cbd->child_idx]); child = LEAF_RAW(child); if (child != NULL) { if (cbd->first_child) print_node_info("node256", (uint64_t)(cbd->node), &(an256->n)); fprintf(my_context.output, "N%" PRIxPTR " -> N%" PRIxPTR " [label=\"%s\"];\n", (uintptr_t)an256, (uintptr_t)child, asciidump(&(hexvals[cbd->child_idx]), 1)); } break; default: break; } return 0; } /* * outv_err -- print error message */ void outv_err(const char *fmt, ...) { va_list ap; va_start(ap, fmt); outv_err_vargs(fmt, ap); va_end(ap); } /* * outv_err_vargs -- print error message */ void outv_err_vargs(const char *fmt, va_list ap) { fprintf(stderr, "error: "); vfprintf(stderr, fmt, ap); if (!strchr(fmt, '\n')) fprintf(stderr, "\n"); } pmdk-1.4.1/src/examples/libpmemcto/libart/arttree.h000066400000000000000000000045261331545616200223210ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * ========================================================================== * * Filename: arttree.h * * Description: implement ART tree using libpmemcto based on libart * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * ========================================================================== */ #ifndef _ARTTREE_H #define _ARTTREE_H #ifdef __cplusplus extern "C" { #endif #include "art.h" #ifdef __FreeBSD__ #define RESET_GETOPT optreset = 1; optind = 1 #else #define RESET_GETOPT optind = 0 #endif #ifdef __cplusplus } #endif #endif /* _ARTTREE_H */ pmdk-1.4.1/src/examples/libpmemcto/life/000077500000000000000000000000001331545616200201355ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemcto/life/.gitignore000066400000000000000000000000051331545616200221200ustar00rootroot00000000000000life pmdk-1.4.1/src/examples/libpmemcto/life/Makefile000066400000000000000000000040661331545616200216030ustar00rootroot00000000000000# # Copyright 2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemcto/life/Makefile -- build the life example # TOP := $(dir $(lastword $(MAKEFILE_LIST)))../../../../ include $(TOP)/src/common.inc NCURSES := $(call check_package, ncurses) ifeq ($(NCURSES),y) PROGS = life else $(info NOTE: Skipping pminvaders and pminvaders2 because ncurses is missing \ -- see src/examples/libpmemcto/life/README for details.) endif LIBS = -lpmemcto -lpmem -pthread ifeq ($(NCURSES),y) LIBS += $(shell $(PKG_CONFIG) --libs ncurses) endif include ../../Makefile.inc life: life.o life_common.o pmdk-1.4.1/src/examples/libpmemcto/life/README000066400000000000000000000010571331545616200210200ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemcto/life/README. This directory contains an example application that implements Conway's Game of Life using libpmemcto. To launch the game: ./life file [iterations] The file with the game session will either be created if it doesn't exist or opened if it contains a valid pool. ** DEPENDENCIES: ** In order to build both variants of the game you need to install ncurses development package. rpm-based systems : ncurses-devel dpkg-based systems: libncursesX-dev (where X is the API/ABI version) pmdk-1.4.1/src/examples/libpmemcto/life/life.c000066400000000000000000000053061331545616200212240ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * life.c -- a simple example which implements Conway's Game of Life */ #include #include #include #include #include #include "life.h" #define WIDTH 64 #define HEIGHT 64 /* * game_draw -- displays game board */ static void game_draw(WINDOW *win, struct game *gp) { for (int x = 0; x < gp->width; x++) { for (int y = 0; y < gp->height; y++) { if (CELL(gp, gp->board, x, y)) mvaddch(x + 1, y + 1, 'O'); else mvaddch(x + 1, y + 1, ' '); } } wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); wrefresh(win); } int main(int argc, const char *argv[]) { if (argc < 2) { fprintf(stderr, "life path [iterations]\n"); exit(1); } unsigned iterations = ~0; /* ~inifinity */ if (argc == 3) iterations = atoi(argv[2]); struct game *gp = game_init(argv[1], WIDTH, HEIGHT, 10); if (gp == NULL) exit(1); initscr(); noecho(); WINDOW *win = newwin(HEIGHT + 2, WIDTH + 2, 0, 0); while (iterations > 0) { game_draw(win, gp); game_next(gp); timeout(500); if (getch() != -1) break; iterations--; } endwin(); pmemcto_close(gp->pcp); return 0; } pmdk-1.4.1/src/examples/libpmemcto/life/life.h000066400000000000000000000041311331545616200212240ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * life.h -- internal definitions for pmemcto life example */ #define LAYOUT_NAME "LIFE" #define POOL_SIZE (2 * PMEMCTO_MIN_POOL) struct game { PMEMctopool *pcp; int width; int height; char *board1; char *board2; char *board; /* points to board1 or board2 */ }; #define X(x, w) (((x) + (w)) % (w)) #define Y(y, h) (((y) + (h)) % (h)) #define CELL(g, b, x, y) (b[Y(y, (g)->height) * (g)->width + X(x, (g)->width)]) struct game *game_init(const char *path, int width, int height, int percent); void game_next(struct game *gp); pmdk-1.4.1/src/examples/libpmemcto/life/life_common.c000066400000000000000000000102141331545616200225660ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * life_common.c -- shared code for pmemcto life examples */ #include #include #include #ifndef _WIN32 #include #endif #include #include "life.h" /* * game_init -- creates/opens the pool and initializes game state */ struct game * game_init(const char *path, int width, int height, int percent) { /* create the pmemcto pool or open it if already exists */ PMEMctopool *pcp = pmemcto_create(path, LAYOUT_NAME, POOL_SIZE, 0666); if (pcp == NULL) pcp = pmemcto_open(path, LAYOUT_NAME); if (pcp == NULL) { fprintf(stderr, "%s", pmemcto_errormsg()); return NULL; } /* get the root object pointer */ struct game *gp = pmemcto_get_root_pointer(pcp); /* check if width/height is the same */ if (gp != NULL) { if (gp->width == width && gp->height == height) { return gp; } else { fprintf(stderr, "board dimensions changed"); pmemcto_free(pcp, gp->board1); pmemcto_free(pcp, gp->board2); pmemcto_free(pcp, gp); } } /* allocate root object */ gp = pmemcto_calloc(pcp, 1, sizeof(*gp)); if (gp == NULL) { fprintf(stderr, "%s", pmemcto_errormsg()); return NULL; } /* save the root object pointer */ pmemcto_set_root_pointer(pcp, gp); gp->pcp = pcp; gp->width = width; gp->height = height; gp->board1 = (char *)pmemcto_malloc(pcp, width * height); if (gp->board1 == NULL) { fprintf(stderr, "%s", pmemcto_errormsg()); return NULL; } gp->board2 = (char *)pmemcto_malloc(pcp, width * height); if (gp->board2 == NULL) { fprintf(stderr, "%s", pmemcto_errormsg()); return NULL; } gp->board = gp->board2; srand((unsigned)time(NULL)); for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) CELL(gp, gp->board, x, y) = (rand() % 100 < percent); return gp; } /* * cell_next -- calculates next state of given cell */ static int cell_next(struct game *gp, char *b, int x, int y) { int alive = CELL(gp, b, x, y); int neighbors = CELL(gp, b, x - 1, y - 1) + CELL(gp, b, x - 1, y) + CELL(gp, b, x - 1, y + 1) + CELL(gp, b, x, y - 1) + CELL(gp, b, x, y + 1) + CELL(gp, b, x + 1, y - 1) + CELL(gp, b, x + 1, y) + CELL(gp, b, x + 1, y + 1); int next = (alive && (neighbors == 2 || neighbors == 3)) || (!alive && (neighbors == 3)); return next; } /* * game_next -- calculates next iteration of the game */ void game_next(struct game *gp) { char *prev = gp->board; char *next = (gp->board == gp->board2) ? gp->board1 : gp->board2; for (int x = 0; x < gp->width; x++) for (int y = 0; y < gp->height; y++) CELL(gp, next, x, y) = cell_next(gp, prev, x, y); gp->board = next; } pmdk-1.4.1/src/examples/libpmemcto/lifesaver/000077500000000000000000000000001331545616200211765ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemcto/lifesaver/README000066400000000000000000000013021331545616200220520ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemcto/lifesaver/README. This directory contains an example a simple screen saver for Windows, which implements Conway's Game of Life. To launch the screen saver: .\lifesaver.scr To install the screen saver, copy the .scr file into your system folder (i.e. C:\Windows\System32), then right-click on the Windows Desktop and select "Personalize" and "Screen Saver". Now, in the dialog box you can select "LifeSaver" from the list. Click "Settings..." to configure the location of the game session file (default is C:\temp\life.cto"). The file with the game session will either be created if it doesn't exist or opened if it contains a valid pool. pmdk-1.4.1/src/examples/libpmemcto/lifesaver/lifesaver.c000066400000000000000000000105241331545616200233240ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * lifesaver.c -- a simple screen saver which implements Conway's Game of Life */ #include #include #include #include #include #include "life.h" #include "resource.h" #define DEFAULT_PATH "c:\\temp\\life.cto" #define TIMER_ID 1 CHAR Path[MAX_PATH]; CHAR szAppName[] = "Life's Screen-Saver"; CHAR szIniFile[] = "lifesaver.ini"; CHAR szParamPath[] = "Data file path"; static int Width; static int Height; /* * game_draw -- displays game board */ void game_draw(HWND hWnd, struct game *gp) { RECT rect; PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); HBITMAP bmp = CreateBitmap(gp->width, gp->height, 1, 8, gp->board); HBRUSH brush = CreatePatternBrush(bmp); GetWindowRect(hWnd, &rect); FillRect(hdc, &rect, brush); DeleteObject(brush); DeleteObject(bmp); EndPaint(hWnd, &ps); } /* * load_config -- loads screen saver config */ static void load_config(void) { DWORD res = GetPrivateProfileString(szAppName, szParamPath, DEFAULT_PATH, Path, sizeof(Path), szIniFile); } /* * ScreenSaverConfigureDialog -- handles configuration dialog window * * XXX: fix saving configuration */ BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hOK; static HWND hPath; HRESULT hr; BOOL res; switch (message) { case WM_INITDIALOG: load_config(); hPath = GetDlgItem(hDlg, IDC_PATH); hOK = GetDlgItem(hDlg, IDC_OK); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_OK: /* write current file path to the .ini file */ res = WritePrivateProfileString(szAppName, szParamPath, Path, szIniFile); /* fall-thru to EndDialog() */ case IDC_CANCEL: EndDialog(hDlg, LOWORD(wParam) == IDC_OK); return TRUE; } } return FALSE; } BOOL RegisterDialogClasses(HANDLE hInst) { return TRUE; } /* * ScreenSaverProc -- screen saver window proc */ LRESULT CALLBACK ScreenSaverProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { static HANDLE hTimer; static struct game *gp; HDC hdc; static RECT rc; switch (iMessage) { case WM_CREATE: Width = GetSystemMetrics(SM_CXSCREEN); Height = GetSystemMetrics(SM_CYSCREEN); load_config(); gp = game_init(Path, Width, Height, 10); hTimer = (HANDLE)SetTimer(hWnd, TIMER_ID, 10, NULL); /* 10ms */ return 0; case WM_ERASEBKGND: hdc = GetDC(hWnd); GetClientRect(hWnd, &rc); FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH)); ReleaseDC(hWnd, hdc); return 0; case WM_TIMER: game_next(gp); InvalidateRect(hWnd, NULL, FALSE); return 0; case WM_PAINT: game_draw(hWnd, gp); return 0; case WM_DESTROY: if (hTimer) KillTimer(hWnd, TIMER_ID); pmemcto_close(gp->pcp); PostQuitMessage(0); return 0; } return (DefScreenSaverProc(hWnd, iMessage, wParam, lParam)); } pmdk-1.4.1/src/examples/libpmemcto/lifesaver/lifesaver.def000066400000000000000000000032741331545616200236440ustar00rootroot00000000000000;;;; Begin Copyright Notice ; ; Copyright 2017, Intel Corporation ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions ; are met: ; ; * Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; ; * Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in ; the documentation and/or other materials provided with the ; distribution. ; ; * Neither the name of the copyright holder nor the names of its ; contributors may be used to endorse or promote products derived ; from this software without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ;;;; End Copyright Notice NAME LIFESAVER.SCR HEAPSIZE 1024 STACKSIZE 4096 EXPORTS ScreenSaverProc ScreenSaverConfigureDialog pmdk-1.4.1/src/examples/libpmemcto/lifesaver/lifesaver.rc000066400000000000000000000041641331545616200235110ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * lifesaver.rc -- resource file for Life screen saver */ #include "winres.h" #include "resource.h" DLG_SCRNSAVECONFIGURE DIALOGEX 6, 18, 279, 58 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Life's Screen-Saver Setup" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN LTEXT "File path",103,5,14,16,8 EDITTEXT IDC_PATH,24,13,204,12,ES_UPPERCASE PUSHBUTTON "OK",IDC_OK,233,12,40,14 PUSHBUTTON "Cancel",IDC_CANCEL,233,34,40,14 END pmdk-1.4.1/src/examples/libpmemcto/lifesaver/lifesaver.vcxproj000066400000000000000000000111661331545616200246000ustar00rootroot00000000000000 Debug x64 Release x64 {73F35C28-811C-4D77-916E-386EB139C001} lifesaver 10.0.14393.0 Application true v140 Application false v140 $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); .scr $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); .scr PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_MBCS;%(PreprocessorDefinitions) $(SolutionDir)\examples\libpmemcto\life;%(AdditionalIncludeDirectories) Windows Scrnsave.lib ;Comctl32.lib;%(AdditionalDependencies) lifesaver.def PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_MBCS;%(PreprocessorDefinitions) $(SolutionDir)\examples\libpmemcto\life;%(AdditionalIncludeDirectories) Windows Scrnsave.lib ;Comctl32.lib;%(AdditionalDependencies) lifesaver.def {1ba340ec-b0b2-438d-a47c-27f86f604133} {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmemcto/lifesaver/lifesaver.vcxproj.filters000066400000000000000000000020401331545616200262360ustar00rootroot00000000000000 {1ec3bc7f-6520-4e71-a0b1-5ba18006d0e1} {f53cd53a-f7da-4d23-86b1-d9356b19b648} Source Files Source Files Header Files Header Files Source Files pmdk-1.4.1/src/examples/libpmemcto/lifesaver/resource.h000066400000000000000000000033761331545616200232070ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * resource.h -- resource file for Life screen saver */ #define VS_VERSION_INFO 1 #define IDC_PATH 1000 #define IDC_OK 1002 #define IDC_CANCEL 1003 #define DLG_SCRNSAVECONFIGURE 2003 pmdk-1.4.1/src/examples/libpmemcto/manpage.c000066400000000000000000000053601331545616200207760ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * manpage.c -- simple example for the libpmemcto man page */ #include #include #include #include #ifndef _WIN32 #include #endif #include #include /* size of the pmemcto pool -- 1 GB */ #define POOL_SIZE ((size_t)(1 << 30)) /* name of our layout in the pool */ #define LAYOUT_NAME "example_layout" struct root { char *str; char *data; }; int main(int argc, char *argv[]) { const char path[] = "/pmem-fs/myfile"; PMEMctopool *pcp; /* create the pmemcto pool or open it if already exists */ pcp = pmemcto_create(path, LAYOUT_NAME, POOL_SIZE, 0666); if (pcp == NULL) pcp = pmemcto_open(path, LAYOUT_NAME); if (pcp == NULL) { perror(path); exit(1); } /* get the root object pointer */ struct root *rootp = pmemcto_get_root_pointer(pcp); if (rootp == NULL) { /* allocate root object */ rootp = pmemcto_malloc(pcp, sizeof(*rootp)); if (rootp == NULL) { perror(pmemcto_errormsg()); exit(1); } /* save the root object pointer */ pmemcto_set_root_pointer(pcp, rootp); rootp->str = pmemcto_strdup(pcp, "Hello World!"); rootp->data = NULL; } /* ... */ pmemcto_close(pcp); } pmdk-1.4.1/src/examples/libpmemcto/manpage.vcxproj000066400000000000000000000107261331545616200222510ustar00rootroot00000000000000 Debug x64 Release x64 {3DEB4FBF-638D-4588-A510-E9A77FF75BB1} manpage 10.0.14393.0 Application true v140 NotSet Application false v140 true NotSet $(Platform)\$(Configuration)\manpage\ pmemcto_$(ProjectName) $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); $(Platform)\$(Configuration)\manpage\ pmemcto_$(ProjectName) $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); Level3 Disabled true 4996 PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_MBCS;%(PreprocessorDefinitions) Level3 MaxSpeed true true true 4996 PMDK_UTF8_API;NTDDI_VERSION=NTDDI_WIN10_RS1;_MBCS;%(PreprocessorDefinitions) true true {1ba340ec-b0b2-438d-a47c-27f86f604133} {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmemcto/manpage.vcxproj.filters000066400000000000000000000007551331545616200237210ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx Source Files pmdk-1.4.1/src/examples/libpmemlog/000077500000000000000000000000001331545616200172125ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemlog/.gitignore000066400000000000000000000000101331545616200211710ustar00rootroot00000000000000manpage pmdk-1.4.1/src/examples/libpmemlog/Makefile000066400000000000000000000033241331545616200206540ustar00rootroot00000000000000# # Copyright 2014-2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemlog/Makefile -- build the libpmemlog examples # PROGS = manpage DIRS = logfile LIBS = -lpmemlog -lpmem -pthread include ../Makefile.inc manpage: manpage.o pmdk-1.4.1/src/examples/libpmemlog/README000066400000000000000000000013131331545616200200700ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemlog/README. This directory contains examples for libpmemlog, the library providing pmem-resident log files. Some of these examples are explained in more detail here: http://pmem.io/pmdk/libpmemlog manpage.c is the example used in the libpmemlog man page. logfile implements a simple log using libpmemlog. To build these examples: make These examples can be built against an installed system using: make LIBDIR=/usr/lib INCDIR=/usr/include If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. Developers new to PMDK are probably looking for libpmemobj. pmdk-1.4.1/src/examples/libpmemlog/logfile/000077500000000000000000000000001331545616200206335ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemlog/logfile/.gitignore000066400000000000000000000000201331545616200226130ustar00rootroot00000000000000addlog printlog pmdk-1.4.1/src/examples/libpmemlog/logfile/Makefile000066400000000000000000000034311331545616200222740ustar00rootroot00000000000000# # Copyright 2014-2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/logfile/Makefile -- build the Persistent Memory Development Kit examples # PROGS = addlog printlog LIBS = -lpmemlog -lpmem -pthread include ../../Makefile.inc addlog: addlog.o printlog: printlog.o addlog.o printlog.o: logentry.h pmdk-1.4.1/src/examples/libpmemlog/logfile/README000066400000000000000000000017131331545616200215150ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemlog/logfile/README. The example in this directory uses persistent memory to implement a simple log file using libpmemlog. To run this example, follow these steps: 0. Build the example with "make". The libraries must be built first (i.e. by running "make" in ../../..). 1. Create the log file. This can be anywhere but the point is it will be a much faster log file if it is created on a pmem-aware file system. For example, if /pmem is the mount point for a pmem-aware file system: $ fallocate -l 1G /pmem/logfile 2. Append to the log file as many times as you like: $ addlog /pmem/logfile "Hello there." $ addlog /pmem/logfile "First line." "Second line." ... 3. Print the contents of the log any time using: $ printlog /pmem/logfile 4. The printlog command will throw away the current log file contents after printing it if given the -t argument: $ printlog -t /pmem/logfile pmdk-1.4.1/src/examples/libpmemlog/logfile/addlog.c000066400000000000000000000076571331545616200222500ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * addlog -- given a log file, append a log entry * * Usage: * fallocate -l 1G /path/to/pm-aware/file * addlog /path/to/pm-aware/file "first line of entry" "second line" */ #include #include #include #include #include #include #include #include #include "logentry.h" int main(int argc, char *argv[]) { PMEMlogpool *plp; struct logentry header; struct iovec *iovp; struct iovec *next_iovp; int iovcnt; if (argc < 3) { fprintf(stderr, "usage: %s filename lines...\n", argv[0]); exit(1); } const char *path = argv[1]; /* create the log in the given file, or open it if already created */ plp = pmemlog_create(path, 0, CREATE_MODE_RW); if (plp == NULL && (plp = pmemlog_open(path)) == NULL) { perror(path); exit(1); } /* fill in the header */ time(&header.timestamp); header.pid = getpid(); /* * Create an iov for pmemlog_appendv(). For each argument given, * allocate two entries (one for the string, one for the newline * appended to the string). Allocate 1 additional entry for the * header that gets prepended to the entry. */ iovcnt = (argc - 2) * 2 + 2; if ((iovp = malloc(sizeof(*iovp) * iovcnt)) == NULL) { perror("malloc"); exit(1); } next_iovp = iovp; /* put the header into iov first */ next_iovp->iov_base = &header; next_iovp->iov_len = sizeof(header); next_iovp++; /* * Now put each arg in, following it with the string "\n". * Calculate a total character count in header.len along the way. */ header.len = 0; for (int arg = 2; arg < argc; arg++) { /* add the string given */ next_iovp->iov_base = argv[arg]; next_iovp->iov_len = strlen(argv[arg]); header.len += next_iovp->iov_len; next_iovp++; /* add the newline */ next_iovp->iov_base = "\n"; next_iovp->iov_len = 1; header.len += 1; next_iovp++; } /* * pad with NULs (at least one) to align next entry to sizeof(long long) * bytes */ int a = sizeof(long long); int len_to_round = 1 + (a - (header.len + 1) % a) % a; char *buf[sizeof(long long)] = {0}; next_iovp->iov_base = buf; next_iovp->iov_len = len_to_round; header.len += len_to_round; next_iovp++; /* atomically add it all to the log */ if (pmemlog_appendv(plp, iovp, iovcnt) < 0) { perror("pmemlog_appendv"); free(iovp); exit(1); } free(iovp); pmemlog_close(plp); } pmdk-1.4.1/src/examples/libpmemlog/logfile/addlog.filters000066400000000000000000000012361331545616200234610ustar00rootroot00000000000000 {7b7d2f5a-464e-4d55-894b-3110e15303f1} {c2e783a4-4f6d-419d-bbf6-1056eddfdd8f} Source Files Header Files pmdk-1.4.1/src/examples/libpmemlog/logfile/addlog.vcxproj000066400000000000000000000053241331545616200235060ustar00rootroot00000000000000 Debug x64 Release x64 {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2} pmemlog 10.0.14393.0 {0b1818eb-bdc8-4865-964f-db8bf05cfd86} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 NotSet Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemlog/logfile/addlog.vcxproj.filters000066400000000000000000000014421331545616200251520ustar00rootroot00000000000000 {d3d73d42-d99e-4314-97df-e9d6289423a5} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {416df294-73b9-4a41-b319-8d0c1922b01b} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Header Files pmdk-1.4.1/src/examples/libpmemlog/logfile/logentry.h000066400000000000000000000034031331545616200226470ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * info prepended to each log entry... */ struct logentry { size_t len; /* length of the rest of the log entry */ time_t timestamp; #ifndef _WIN32 pid_t pid; #else int pid; #endif }; pmdk-1.4.1/src/examples/libpmemlog/logfile/printlog.c000066400000000000000000000060561331545616200226440ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * printlog -- given a log file, print the entries * * Usage: * printlog [-t] /path/to/pm-aware/file * * -t option means truncate the file after printing it. */ #include #include #include #include #include #include #include #include "logentry.h" /* * printlog -- callback function called when walking the log */ static int printlog(const void *buf, size_t len, void *arg) { /* first byte after log contents */ const void *endp = (char *)buf + len; /* for each entry in the log... */ while (buf < endp) { struct logentry *headerp = (struct logentry *)buf; buf = (char *)buf + sizeof(struct logentry); /* print the header */ printf("Entry from pid: %d\n", headerp->pid); printf(" Created: %s", ctime(&headerp->timestamp)); printf(" Contents:\n"); /* print the log data itself, it is NUL-terminated */ printf("%s", (char *)buf); buf = (char *)buf + headerp->len; } return 0; } int main(int argc, char *argv[]) { int ind = 1; int tflag = 0; PMEMlogpool *plp; if (argc > 2) { if (strcmp(argv[1], "-t") == 0) { tflag = 1; ind++; } else { fprintf(stderr, "usage: %s [-t] file\n", argv[0]); exit(1); } } const char *path = argv[ind]; if ((plp = pmemlog_open(path)) == NULL) { perror(path); exit(1); } /* the rest of the work happens in printlog() above */ pmemlog_walk(plp, 0, printlog, NULL); if (tflag) pmemlog_rewind(plp); pmemlog_close(plp); } pmdk-1.4.1/src/examples/libpmemlog/logfile/printlog.filters000066400000000000000000000012401331545616200240600ustar00rootroot00000000000000 {7b7d2f5a-464e-4d55-894b-3110e15303f1} {c2e783a4-4f6d-419d-bbf6-1056eddfdd8f} Source Files Header Files pmdk-1.4.1/src/examples/libpmemlog/logfile/printlog.vcxproj000066400000000000000000000052561331545616200241160ustar00rootroot00000000000000 Debug x64 Release x64 {C3CEE34C-29E0-4A22-B258-3FBAF662AA19} pmemlog 10.0.14393.0 {0b1818eb-bdc8-4865-964f-db8bf05cfd86} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemlog/logfile/printlog.vcxproj.filters000066400000000000000000000014441331545616200255600ustar00rootroot00000000000000 {a0af7281-6084-422f-946c-e05d18224229} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {9eebac3f-530b-4b3b-b0c7-68f43650d681} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Header Files pmdk-1.4.1/src/examples/libpmemlog/manpage.c000066400000000000000000000056201331545616200207710ustar00rootroot00000000000000/* * Copyright 2014-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * manpage.c -- simple example for the libpmemlog man page */ #include #include #include #include #ifndef _WIN32 #include #endif #include #include /* size of the pmemlog pool -- 1 GB */ #define POOL_SIZE ((size_t)(1 << 30)) /* * printit -- log processing callback for use with pmemlog_walk() */ static int printit(const void *buf, size_t len, void *arg) { fwrite(buf, len, 1, stdout); return 0; } int main(int argc, char *argv[]) { const char path[] = "/pmem-fs/myfile"; PMEMlogpool *plp; size_t nbyte; char *str; /* create the pmemlog pool or open it if it already exists */ plp = pmemlog_create(path, POOL_SIZE, 0666); if (plp == NULL) plp = pmemlog_open(path); if (plp == NULL) { perror(path); exit(1); } /* how many bytes does the log hold? */ nbyte = pmemlog_nbyte(plp); printf("log holds %zu bytes\n", nbyte); /* append to the log... */ str = "This is the first string appended\n"; if (pmemlog_append(plp, str, strlen(str)) < 0) { perror("pmemlog_append"); exit(1); } str = "This is the second string appended\n"; if (pmemlog_append(plp, str, strlen(str)) < 0) { perror("pmemlog_append"); exit(1); } /* print the log contents */ printf("log contains:\n"); pmemlog_walk(plp, 0, printit, NULL); pmemlog_close(plp); } pmdk-1.4.1/src/examples/libpmemlog/manpage.vcxproj000066400000000000000000000051071331545616200222420ustar00rootroot00000000000000 Debug x64 Release x64 {9FF51F3E-AF36-4F45-A797-C5F03A090298} pememlog 10.0.14393.0 Application true v140 Application false v140 true $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest {0b1818eb-bdc8-4865-964f-db8bf05cfd86} {9e9e3d25-2139-4a5d-9200-18148ddead45} pmdk-1.4.1/src/examples/libpmemlog/manpage.vcxproj.filters000066400000000000000000000012541331545616200237100ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files pmdk-1.4.1/src/examples/libpmemobj++/000077500000000000000000000000001331545616200173315ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/Makefile000066400000000000000000000033251331545616200207740ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemobj++/Makefile -- build the libpmemobj++ examples # include ../../common.inc DIRS = queue pman map_cli panaconda pmpong doc_snippets include ../Makefile.inc pmdk-1.4.1/src/examples/libpmemobj++/README000066400000000000000000000010601331545616200202060ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemobj++/README. This directory contains examples for libpmemobj++, the library providing a transactional object store for pmem. Some of these examples are explained in more detail here: http://pmem.io/pmdk/cpp_obj/ To build these examples: make These examples can be built against an installed system using: make LIBDIR=/usr/lib INCDIR=/usr/include If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/000077500000000000000000000000001331545616200220235ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/Makefile000066400000000000000000000034701331545616200234670ustar00rootroot00000000000000# # Copyright 2016-2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # include ../../Makefile.inc TARGETS = persistent.o make_persistent.o pool.o transaction.o ifeq ($(call check_cxx_chrono), y) TARGETS += mutex.o else $(info NOTE: Skipping C++ chrono examples because of compiler/stdc++ issues) endif all: $(TARGETS) libsnippets.o: $(TARGETS) pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/doc_snippets.vcxproj000066400000000000000000000056761331545616200261500ustar00rootroot00000000000000 Debug x64 Release x64 {8DB4158E-96EE-4DE5-A425-C9638F50B9ED} pmemobj 10.0.14393.0 StaticLibrary true v140 StaticLibrary false v140 true $(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest 4101 true 4101 true pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/doc_snippets.vcxproj.filters000066400000000000000000000015451331545616200276060ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx Source Files Source Files Source Files Source Files Source Files pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/make_persistent.cpp000066400000000000000000000156531331545616200257360ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * make_persistent.cpp -- C++ documentation snippets. */ //! [make_example] #include #include #include #include #include #include using namespace pmem::obj; void make_persistent_example() { struct compound_type { compound_type(int val, double dval) : some_variable(val), some_other_variable(dval) { } void set_some_variable(int val) { some_variable = val; } p some_variable; p some_other_variable; }; // pool root structure struct root { persistent_ptr comp; // }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes transaction::exec_tx(pop, [&] { // allocation with constructor argument passing proot->comp = make_persistent(1, 2.0); // transactionally delete the object, ~compound_type() is called delete_persistent(proot->comp); }); // throws an transaction_scope_error exception auto arr1 = make_persistent(2, 15.0); delete_persistent(arr1); } //! [make_example] //! [make_array_example] #include #include #include #include #include #include using namespace pmem::obj; void make_persistent_array_example() { struct compound_type { compound_type() : some_variable(0), some_other_variable(0) { } void set_some_variable(int val) { some_variable = val; } p some_variable; p some_other_variable; }; // pool root structure struct root { persistent_ptr comp; // }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes transaction::exec_tx(pop, [&] { // allocate an array of 20 objects - compound_type must be // default constructible proot->comp = make_persistent(20); // another allocation method auto arr1 = make_persistent(); // transactionally delete arrays , ~compound_type() is called delete_persistent(proot->comp, 20); delete_persistent(arr1); }); // throws an transaction_scope_error exception auto arr1 = make_persistent(); delete_persistent(arr1); } //! [make_array_example] //! [make_atomic_example] #include #include #include #include #include #include using namespace pmem::obj; void make_persistent_atomic_example() { struct compound_type { compound_type(int val, double dval) : some_variable(val), some_other_variable(dval) { } void set_some_variable(int val) { some_variable = val; } p some_variable; p some_other_variable; }; // pool root structure struct root { persistent_ptr comp; // }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes // atomic allocation and construction with arguments passing make_persistent_atomic(pop, proot->comp, 1, 2.0); // atomic object deallocation, ~compound_type() is not called delete_persistent(proot->comp); // error prone cases transaction::exec_tx(pop, [&] { // possible invalid state in case of transaction abort make_persistent_atomic(pop, proot->comp, 1, 1.3); delete_persistent_atomic(proot->comp); }); } //! [make_atomic_example] //! [make_array_atomic_example] #include #include #include #include #include #include using namespace pmem::obj; void make_persistent_array_atomic_example() { struct compound_type { compound_type() : some_variable(0), some_other_variable(0) { } void set_some_variable(int val) { some_variable = val; } p some_variable; p some_other_variable; }; // pool root structure struct root { persistent_ptr comp; // }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes // atomic array allocation and construction - the compound_type has to // be default constructible make_persistent_atomic(pop, proot->comp, 20); persistent_ptr arr; make_persistent_atomic(pop, arr); // atomic array deallocation, no destructor being called delete_persistent_atomic(proot->comp, 20); delete_persistent_atomic(arr); // error prone cases transaction::exec_tx(pop, [&] { // possible invalid state in case of transaction abort make_persistent_atomic(pop, proot->comp, 30); delete_persistent_atomic(proot->comp, 30); }); } //! [make_array_atomic_example] pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/mutex.cpp000066400000000000000000000107161331545616200236760ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * mutex.cpp -- C++ documentation snippets. */ //! [unique_guard_example] #include #include #include #include namespace nvobj = pmem::obj; void unique_guard_example() { // pool root structure struct root { nvobj::mutex pmutex; }; // create a pmemobj pool auto pop = nvobj::pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes std::lock_guard guard(proot->pmutex); std::unique_lock other_guard(proot->pmutex); } //! [unique_guard_example] //! [shared_mutex_example] #include #include #include #include namespace nvobj = pmem::obj; void shared_mutex_example() { // pool root structure struct root { nvobj::shared_mutex pmutex; }; // create a pmemobj pool auto pop = nvobj::pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes proot->pmutex.lock_shared(); std::unique_lock guard(proot->pmutex); } //! [shared_mutex_example] //! [timed_mutex_example] #include #include #include #include namespace nvobj = pmem::obj; void timed_mutex_example() { // pool root structure struct root { nvobj::timed_mutex pmutex; }; // create a pmemobj pool auto pop = nvobj::pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); const auto timeout = std::chrono::milliseconds(100); // typical usage schemes proot->pmutex.try_lock_for(timeout); proot->pmutex.try_lock_until(std::chrono::steady_clock::now() + timeout); } //! [timed_mutex_example] //! [cond_var_example] #include #include #include #include #include #include namespace nvobj = pmem::obj; void cond_var_example() { // pool root structure struct root { nvobj::mutex pmutex; nvobj::condition_variable cond; int counter; }; // create a pmemobj pool auto pop = nvobj::pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // run worker to bump up the counter std::thread worker([&] { std::unique_lock lock(proot->pmutex); while (proot->counter < 1000) ++proot->counter; // unlock before notifying to avoid blocking on waiting thread lock.unlock(); // notify the waiting thread proot->cond.notify_one(); }); std::unique_lock lock(proot->pmutex); // wait on condition variable proot->cond.wait(lock, [&] { return proot->counter >= 1000; }); worker.join(); } //! [cond_var_example] pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/persistent.cpp000066400000000000000000000073611331545616200247360ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * persistent.cpp -- C++ documentation snippets. */ //! [p_property_example] #include #include #include #include using namespace pmem::obj; void p_property_example() { struct compound_type { void set_some_variable(int val) { some_variable = val; } int some_variable; double some_other_variable; }; // pool root structure static struct root { p counter; // this is OK p whoops; // this is hard to use } proot; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); // typical usage schemes transaction::exec_tx(pop, [&] { proot.counter = 12; // atomic // one way to change `whoops` proot.whoops.get_rw().set_some_variable(2); proot.whoops.get_rw().some_other_variable = 3.0; }); // Changing a p<> variable outside of a transaction is a volatile // modification. No way to ensure persistence in case of power failure. proot.counter = 12; } //! [p_property_example] //! [persistent_ptr_example] #include #include #include #include #include using namespace pmem::obj; void persistent_ptr_example() { struct compound_type { void set_some_variable(int val) { some_variable = val; } int some_variable; double some_other_variable; }; // pool root structure struct root { persistent_ptr comp; } proot; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); // typical usage schemes transaction::exec_tx(pop, [&] { proot.comp = make_persistent(); // allocation proot.comp->set_some_variable(12); // call function proot.comp->some_other_variable = 2.3; // set variable }); // reading from the persistent_ptr compound_type tmp = *proot.comp; (void)tmp; // Changing a persistent_ptr<> variable outside of a transaction is a // volatile modification. No way to ensure persistence in case of power // failure. proot.comp->some_variable = 12; } //! [persistent_ptr_example] pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/pool.cpp000066400000000000000000000071231331545616200235030ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pool.cpp -- C++ documentation snippets. */ //! [pool_example] #include #include #include #include using namespace pmem::obj; void pool_example() { // pool root structure struct root { p some_array[42]; p some_other_array[42]; p some_variable; }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); // close a pmemobj pool pop.close(); // or open a pmemobj pool pop = pool::open("poolfile", "layout"); // typical usage schemes auto root_obj = pop.get_root(); // low-level memory manipulation root_obj->some_variable = 3.2; pop.persist(root_obj->some_variable); pop.memset_persist(root_obj->some_array, 2, sizeof(root_obj->some_array)); pop.memcpy_persist(root_obj->some_other_array, root_obj->some_array, sizeof(root_obj->some_array)); pop.close(); // check pool consistency pool::check("poolfile", "layout"); } //! [pool_example] //! [pool_base_example] #include #include #include #include using namespace pmem::obj; void pool_base_example() { struct some_struct { p some_array[42]; p some_other_array[42]; p some_variable; }; // create a pmemobj pool auto pop = pool_base::create("poolfile", "", PMEMOBJ_MIN_POOL); // close a pmemobj pool pop.close(); // or open a pmemobj pool pop = pool_base::open("poolfile", ""); // no "root" object available in pool_base persistent_ptr pval; make_persistent_atomic(pop, pval); // low-level memory manipulation pval->some_variable = 3; pop.persist(pval->some_variable); pop.memset_persist(pval->some_array, 2, sizeof(pval->some_array)); pop.memcpy_persist(pval->some_other_array, pval->some_array, sizeof(pval->some_array)); pop.close(); // check pool consistency pool_base::check("poolfile", ""); } //! [pool_base_example] pmdk-1.4.1/src/examples/libpmemobj++/doc_snippets/transaction.cpp000066400000000000000000000135151331545616200250610ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * transaction.cpp -- C++ documentation snippets. */ /* * The following might be necessary to compile the examples on older compilers. */ #if !defined(__cpp_lib_uncaught_exceptions) && !defined(_MSC_VER) || \ (_MSC_VER < 1900) #define __cpp_lib_uncaught_exceptions 201411 namespace std { int uncaught_exceptions() noexcept { return 0; } } /* namespace std */ #endif /* __cpp_lib_uncaught_exceptions */ //! [general_tx_example] #include #include #include #include #include #include #include using namespace pmem::obj; void general_tx_example() { // pool root structure struct root { mutex pmutex; shared_mutex shared_pmutex; p count; persistent_ptr another_root; }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); // typical usage schemes try { // take locks and start a transaction transaction::exec_tx(pop, [&]() { // atomically allocate objects proot->another_root = make_persistent(); // atomically modify objects proot->count++; }, proot->pmutex, proot->shared_pmutex); } catch (pmem::transaction_error &te) { // a transaction error occurred, transaction got aborted // reacquire locks if necessary } catch (...) { // some other exception got propagated from within the tx // reacquire locks if necessary } } //! [general_tx_example] //! [manual_tx_example] #include #include #include #include #include #include #include using namespace pmem::obj; int manual_tx_example() { // pool root structure struct root { mutex pmutex; shared_mutex shared_pmutex; p count; persistent_ptr another_root; }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); try { transaction::manual tx(pop, proot->pmutex, proot->shared_pmutex); // atomically allocate objects proot->another_root = make_persistent(); // atomically modify objects proot->count++; // It's necessary to commit the transaction manually and // it has to be the last operation in the transaction. transaction::commit(); } catch (pmem::transaction_error &te) { // an internal transaction error occurred, tx aborted // reacquire locks if necessary } catch (...) { // some other exception thrown, tx aborted // reacquire locks if necessary } // In complex cases with library calls, remember to check the status of // the previous transaction. return transaction::get_last_tx_error(); } //! [manual_tx_example] //! [automatic_tx_example] #include #include #include #include #include #include #include using namespace pmem::obj; int automatic_tx_example() { // pool root structure struct root { mutex pmutex; shared_mutex shared_pmutex; p count; persistent_ptr another_root; }; // create a pmemobj pool auto pop = pool::create("poolfile", "layout", PMEMOBJ_MIN_POOL); auto proot = pop.get_root(); try { transaction::automatic tx(pop, proot->pmutex, proot->shared_pmutex); // atomically allocate objects proot->another_root = make_persistent(); // atomically modify objects proot->count++; // manual transaction commit is no longer necessary } catch (pmem::transaction_error &te) { // an internal transaction error occurred, tx aborted // reacquire locks if necessary } catch (...) { // some other exception thrown, tx aborted // reacquire locks if necessary } // In complex cases with library calls, remember to check the status of // the previous transaction. return transaction::get_last_tx_error(); } //! [automatic_tx_example] pmdk-1.4.1/src/examples/libpmemobj++/list.hpp000066400000000000000000000101541331545616200210160ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * list.hpp -- Implementation of list */ #include #include #include #include namespace examples { template class list { class list_entry { public: list_entry() = delete; list_entry(pmem::obj::persistent_ptr previous, pmem::obj::persistent_ptr value) { val = value; next = nullptr; prev = previous; } pmem::obj::persistent_ptr prev; pmem::obj::persistent_ptr next; pmem::obj::persistent_ptr val; }; public: list() { head = nullptr; tail = head; len = 0; } /** * Push back the new element. */ void push_back(pmem::obj::persistent_ptr val) { auto tmp = pmem::obj::make_persistent(tail, val); if (head == nullptr) head = tmp; else tail->next = tmp; tail = tmp; ++len; } /** * Pop the last element out from the list and return * the pointer to it */ pmem::obj::persistent_ptr pop_back() { assert(head != nullptr); auto tmp = tail; tail = tmp->prev; if (tail == nullptr) head = tail; else tail->next = nullptr; return tmp->val; } /** * Return the pointer to the next element */ pmem::obj::persistent_ptr erase(unsigned id) { return remove_elm(get_elm(id)); } /* clear - clear the whole list */ void clear() { while (head != nullptr) { auto e = head; head = remove_elm(e); } } /** * Get element with given id in list */ pmem::obj::persistent_ptr get(unsigned id) { auto elm = get_elm(id); if (elm == nullptr) return nullptr; return elm->val; } /** * Return number of elements in list */ unsigned size() const { return len; } private: pmem::obj::persistent_ptr get_elm(unsigned id) { if (id >= len) return nullptr; auto tmp = head; for (unsigned i = 0; i < id; i++) tmp = tmp->next; return tmp; } pmem::obj::persistent_ptr remove_elm(pmem::obj::persistent_ptr elm) { assert(elm != nullptr); auto tmp = elm->next; pmem::obj::delete_persistent(elm->val); /* removing item is head */ if (elm == head) head = elm->next; else elm->prev->next = elm->next; /* removing item is tail */ if (elm == tail) tail = elm->prev; else elm->next->prev = elm->prev; --len; pmem::obj::delete_persistent(elm); return tmp; } pmem::obj::p len; pmem::obj::persistent_ptr head; pmem::obj::persistent_ptr tail; }; }; pmdk-1.4.1/src/examples/libpmemobj++/map_cli/000077500000000000000000000000001331545616200207355ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/map_cli/.gitignore000066400000000000000000000000101331545616200227140ustar00rootroot00000000000000map_cli pmdk-1.4.1/src/examples/libpmemobj++/map_cli/Makefile000066400000000000000000000032261331545616200224000ustar00rootroot00000000000000# # Copyright 2015-2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # PROGS = map_cli LIBS = -lpmemobj -lpmem -pthread COMPILE_LANG = cpp include ../../Makefile.inc map_cli: map_cli.o pmdk-1.4.1/src/examples/libpmemobj++/map_cli/ctree_map_persistent.hpp000066400000000000000000000233561331545616200256760ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EXAMPLES_CTREE_MAP_PERSISTENT_HPP #define EXAMPLES_CTREE_MAP_PERSISTENT_HPP #include #include #include #include #include #include #include #include #include #include #include #define BIT_IS_SET(n, i) (!!((n) & (1ULL << (i)))) namespace nvobj = pmem::obj; namespace examples { /** * C++ implementation of a persistent ctree. * * Based on the volatile version. This version was implemented to show how much * effort is needed to convert a volatile structure into a persistent one using * C++ obj bindings. All API functions are atomic in respect to persistency. */ template class ctree_map_p { public: /** Convenience typedef for the key type. */ typedef K key_type; /** Convenience typedef for the value type. */ typedef nvobj::persistent_ptr value_type; /** Convenience typedef for the callback function. */ typedef std::function callback; /** * Default constructor. */ ctree_map_p() { auto pop = nvobj::pool_by_vptr(this); nvobj::transaction::exec_tx(pop, [&] { this->root = nvobj::make_persistent(); }); } /** * Insert or update the given value under the given key. * * The map takes ownership of the value. * * @param key The key to insert under. * @param value The value to be inserted. * * @return 0 on success, negative values on error. */ int insert(key_type key, value_type value) { auto dest_entry = root; while (dest_entry->inode != nullptr) { auto n = dest_entry->inode; dest_entry = n->entries[BIT_IS_SET(key, n->diff)]; } entry e(key, value); auto pop = nvobj::pool_by_vptr(this); nvobj::transaction::exec_tx(pop, [&] { if (dest_entry->key == 0 || dest_entry->key == key) { nvobj::delete_persistent(dest_entry->value); *dest_entry = e; } else { insert_leaf(&e, find_crit_bit(dest_entry->key, key)); } }); return 0; } /** * Allocating insert. * * Creates a new value_type instance and inserts it into the tree. * * @param key The key to insert under. * @param args variadic template parameter for object construction * arguments. * * @return 0 on success, negative values on error. */ template int insert_new(key_type key, const Args &... args) { auto pop = nvobj::pool_by_vptr(this); nvobj::transaction::exec_tx(pop, [&] { return insert(key, nvobj::make_persistent(args...)); }); return -1; } /** * Remove a value from the tree. * * The tree no longer owns the value. * * @param key The key for which the value will be removed. * * @return The value if it is in the tree, nullptr otherwise. */ value_type remove(key_type key) { nvobj::persistent_ptr parent = nullptr; auto leaf = get_leaf(key, &parent); if (leaf == nullptr) return nullptr; auto ret = leaf->value; auto pop = nvobj::pool_by_vptr(this); nvobj::transaction::exec_tx(pop, [&] { if (parent == nullptr) { leaf->key = 0; leaf->value = nullptr; } else { auto n = parent->inode; *parent = *( n->entries[parent->inode->entries[0] ->key == leaf->key]); /* cleanup entries and the unnecessary node */ nvobj::delete_persistent(n->entries[0]); nvobj::delete_persistent(n->entries[1]); nvobj::delete_persistent(n); } }); return ret; } /** * Remove entry from tree and deallocate it. * * @param key The key denoting the entry to be removed. * * @return 0 on success, negative values on error. */ int remove_free(key_type key) { auto pop = nvobj::pool_by_vptr(this); nvobj::transaction::exec_tx( pop, [&] { nvobj::delete_persistent(remove(key)); }); return 0; } /** * Clear the tree and deallocate all entries. */ int clear() { auto pop = nvobj::pool_by_vptr(this); nvobj::transaction::exec_tx(pop, [&] { if (this->root->inode) { this->root->inode->clear(); nvobj::delete_persistent( this->root->inode); this->root->inode = nullptr; } nvobj::delete_persistent(this->root->value); this->root->value = nullptr; this->root->key = 0; }); return 0; } /** * Return the value from the tree for the given key. * * @param key The key for which the value will be returned. * * @return The value if it is in the tree, nullptr otherwise. */ value_type get(key_type key) { auto ret = get_leaf(key, nullptr); return ret ? ret->value : nullptr; } /** * Check if an entry for the given key is in the tree. * * @param key The key to check. * * @return 0 on */ int lookup(key_type key) const { return get(key) != nullptr; } /** * Call clb for each element in the tree. * * @param clb The callback to be called. * @param args The arguments forwarded to the callback. * * @return 0 if tree empty, clb return value otherwise. */ int foreach (callback clb, void *args) { if (is_empty()) return 0; return foreach_node(root, clb, args); } /** * Check if tree is empty. * * @return 1 if empty, 0 otherwise. */ int is_empty() const { return root->value == nullptr && root->inode == nullptr; } /** * Check tree consistency. * * @return 0 on success, negative values on error. */ int check() const { return 0; } /** * Destructor. */ ~ctree_map_p() { clear(); } private: struct node; /* * Entry holding the value. */ struct entry { entry() : key(0), inode(nullptr), value(nullptr) { } entry(key_type _key, value_type _value) : key(_key), inode(nullptr), value(_value) { } nvobj::p key; nvobj::persistent_ptr inode; value_type value; void clear() { if (inode) { inode->clear(); nvobj::delete_persistent(inode); inode = nullptr; } nvobj::delete_persistent(value); value = nullptr; } }; /* * Internal node pointing to two entries. */ struct node { node() : diff(0) { entries[0] = nullptr; entries[1] = nullptr; } nvobj::p diff; /* most significant differing bit */ nvobj::persistent_ptr entries[2]; void clear() { if (entries[0]) { entries[0]->clear(); nvobj::delete_persistent(entries[0]); entries[0] = nullptr; } if (entries[1]) { entries[1]->clear(); nvobj::delete_persistent(entries[1]); entries[1] = nullptr; } } }; /* * Find critical bit. */ static int find_crit_bit(key_type lhs, key_type rhs) { return find_last_set_64(lhs ^ rhs); } /* * Insert leaf into the tree. */ void insert_leaf(const entry *e, int diff) { auto new_node = nvobj::make_persistent(); new_node->diff = diff; int d = BIT_IS_SET(e->key, new_node->diff); new_node->entries[d] = nvobj::make_persistent(*e); auto dest_entry = root; while (dest_entry->inode != nullptr) { auto n = dest_entry->inode; if (n->diff < new_node->diff) break; dest_entry = n->entries[BIT_IS_SET(e->key, n->diff)]; } new_node->entries[!d] = nvobj::make_persistent(*dest_entry); dest_entry->key = 0; dest_entry->inode = new_node; dest_entry->value = nullptr; } /* * Fetch leaf from the tree. */ nvobj::persistent_ptr get_leaf(key_type key, nvobj::persistent_ptr *parent) { auto n = root; nvobj::persistent_ptr p = nullptr; while (n->inode != nullptr) { p = n; n = n->inode->entries[BIT_IS_SET(key, n->inode->diff)]; } if (n->key == key) { if (parent) *parent = p; return n; } return nullptr; } /* * Recursive foreach on nodes. */ int foreach_node(const nvobj::persistent_ptr e, callback clb, void *arg) { int ret = 0; if (e->inode != nullptr) { auto n = e->inode; if (foreach_node(n->entries[0], clb, arg) == 0) foreach_node(n->entries[1], clb, arg); } else { ret = clb(e->key, e->value, arg); } return ret; } /* Tree root */ nvobj::persistent_ptr root; }; } /* namespace examples */ #endif /* EXAMPLES_CTREE_MAP_PERSISTENT_HPP */ pmdk-1.4.1/src/examples/libpmemobj++/map_cli/ctree_map_transient.hpp000066400000000000000000000201571331545616200255010ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EXAMPLES_CTREE_MAP_VOLATILE_HPP #define EXAMPLES_CTREE_MAP_VOLATILE_HPP #include #include #include #include #ifdef _WIN32 #include #endif #define BIT_IS_SET(n, i) (!!((n) & (1ULL << (i)))) namespace examples { /** * C++ implementation of a volatile ctree. * * Based on the C implementation. */ template class ctree_map_transient { public: /** Convenience typedef for the key type. */ typedef K key_type; /** Convenience typedef for the value type. */ typedef T *value_type; /** Convenience typedef for the callback function. */ typedef std::function callback; /** * Default constructor. */ ctree_map_transient() : root(new entry()) { } /** * Insert or update the given value under the given key. * * The map takes ownership of the value. * * @param key The key to insert under. * @param value The value to be inserted. * * @return 0 on success, negative values on error. */ int insert(uint64_t key, value_type value) { auto dest_entry = root; while (dest_entry->inode != nullptr) { auto n = dest_entry->inode; dest_entry = n->entries[BIT_IS_SET(key, n->diff)]; } entry e(key, value); if (dest_entry->key == 0 || dest_entry->key == key) { delete dest_entry->value; *dest_entry = e; } else { insert_leaf(&e, ctree_map_transient::find_crit_bit( dest_entry->key, key)); } return 0; } /** * Allocating insert. * * Creates a new value_type instance and inserts it into the tree. * * @param key The key to insert under. * @param args variadic template parameter for object construction * arguments. * * @return 0 on success, negative values on error. */ template int insert_new(key_type key, const Args &... args) { return insert(key, new T(args...)); } /** * Remove a value from the tree. * * The tree no longer owns the value. * * @param key The key for which the value will be removed. * * @return The value if it is in the tree, nullptr otherwise. */ value_type remove(key_type key) { entry *parent = nullptr; auto leaf = get_leaf(key, &parent); if (leaf == nullptr) return nullptr; auto ret = leaf->value; if (parent == nullptr) { leaf->key = 0; leaf->value = nullptr; } else { auto n = parent->inode; *parent = *(n->entries[parent->inode->entries[0]->key == leaf->key]); /* cleanup both entries and the unnecessary node */ delete n->entries[0]; delete n->entries[1]; delete n; } return ret; } /** * Remove entry from tree and deallocate it. * * @param key The key denoting the entry to be removed. * * @return 0 on success, negative values on error. */ int remove_free(key_type key) { delete remove(key); return 0; } /** * Clear the tree and deallocate all entries. */ int clear() { if (root->inode) { root->inode->clear(); delete root->inode; root->inode = nullptr; } delete root->value; root->value = nullptr; root->key = 0; return 0; } /** * Return the value from the tree for the given key. * * @param key The key for which the value will be returned. * * @return The value if it is in the tree, nullptr otherwise. */ value_type get(key_type key) { auto ret = get_leaf(key, nullptr); return ret ? ret->value : nullptr; } /** * Check if an entry for the given key is in the tree. * * @param key The key to check. * * @return 0 on */ int lookup(key_type key) const { return get(key) != nullptr; } /** * Call clb for each element in the tree. * * @param clb The callback to be called. * @param args The arguments forwarded to the callback. * * @return 0 if tree empty, clb return value otherwise. */ int foreach (callback clb, void *args) { if (is_empty()) return 0; return foreach_node(root, clb, args); } /** * Check if tree is empty. * * @return 1 if empty, 0 otherwise. */ int is_empty() const { return root->value == nullptr && root->inode == nullptr; } /** * Check tree consistency. * * @return 0 on success, negative values on error. */ int check() const { return 0; } /** * Destructor. */ ~ctree_map_transient() { clear(); delete root; } private: struct node; /* * Entry holding the value. */ struct entry { entry() : key(0), inode(nullptr), value(nullptr) { } entry(key_type _key, value_type _value) : key(_key), inode(nullptr), value(_value) { } key_type key; node *inode; value_type value; /* * Clear the entry. */ void clear() { if (inode) { inode->clear(); delete inode; } delete value; } }; /* * Internal node pointing to two entries. */ struct node { node() : diff(0) { entries[0] = nullptr; entries[1] = nullptr; } int diff; /* most significant differing bit */ entry *entries[2]; /* * Clear the node. */ void clear() { if (entries[0]) { entries[0]->clear(); delete entries[0]; } if (entries[1]) { entries[1]->clear(); delete entries[1]; } } }; /* * Find critical bit. */ static int find_crit_bit(key_type lhs, key_type rhs) { return find_last_set_64(lhs ^ rhs); } /* * Insert leaf into the tree. */ void insert_leaf(const entry *e, int diff) { auto new_node = new node(); new_node->diff = diff; int d = BIT_IS_SET(e->key, new_node->diff); new_node->entries[d] = new entry(*e); auto dest_entry = root; while (dest_entry->inode != nullptr) { auto n = dest_entry->inode; if (n->diff < new_node->diff) break; dest_entry = n->entries[BIT_IS_SET(e->key, n->diff)]; } new_node->entries[!d] = new entry(*dest_entry); dest_entry->key = 0; dest_entry->inode = new_node; dest_entry->value = nullptr; } /* * Fetch leaf from the tree. */ entry * get_leaf(uint64_t key, entry **parent) { auto n = root; entry *p = nullptr; while (n->inode != nullptr) { p = n; n = n->inode->entries[BIT_IS_SET(key, n->inode->diff)]; } if (n->key == key) { if (parent) *parent = p; return n; } return nullptr; } /* * Recursive foreach on nodes. */ int foreach_node(const entry *e, callback clb, void *arg) { int ret = 0; if (e->inode != nullptr) { auto n = e->inode; if (foreach_node(n->entries[0], clb, arg) == 0) foreach_node(n->entries[1], clb, arg); } else { ret = clb(e->key, e->value, arg); } return ret; } /* Tree root */ entry *root; }; } /* namespace examples */ #endif /* EXAMPLES_CTREE_MAP_VOLATILE_HPP */ pmdk-1.4.1/src/examples/libpmemobj++/map_cli/map_cli.cpp000066400000000000000000000147061331545616200230550ustar00rootroot00000000000000/* * Copyright 2016-2018, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "ctree_map_transient.hpp" #include #include #include #include #include #include namespace { using pmem::obj::persistent_ptr; using pmem::obj::make_persistent; using pmem::obj::transaction; using pmem::obj::delete_persistent; using pmem::obj::pool; using pmem::obj::pool_base; /* convenience typedefs */ typedef long long value_t; typedef uint64_t key_type; typedef examples::ctree_map_p pmap; typedef examples::ctree_map_transient vmap; const std::string LAYOUT = ""; /* available map operations */ enum queue_op { UNKNOWN_QUEUE_OP, MAP_INSERT, MAP_INSERT_NEW, MAP_GET, MAP_REMOVE, MAP_REMOVE_FREE, MAP_CLEAR, MAP_PRINT, MAX_QUEUE_OP }; /* queue operations strings */ const char *ops_str[MAX_QUEUE_OP] = {"", "insert", "insert_new", "get", "remove", "remove_free", "clear", "print"}; /* * parse_queue_op -- parses the operation string and returns matching queue_op */ queue_op parse_queue_op(const char *str) { for (int i = 0; i < MAX_QUEUE_OP; ++i) if (strcmp(str, ops_str[i]) == 0) return (queue_op)i; return UNKNOWN_QUEUE_OP; } struct root { persistent_ptr ptree; }; /* * printer -- (internal) print the value for the given key */ template int printer(key_type key, T value, void *) { std::cout << "map[" << key << "] = " << *value << std::endl; return 0; } /* * insert -- (internal) insert value into the map */ template void insert(pool_base pop, T &map, char *argv[], int &argn) { map->insert(atoll(argv[argn]), new value_t(atoll(argv[argn + 1]))); argn += 2; } /* * remove -- (internal) remove value from map */ template void remove(pool_base pop, T &map, char *argv[], int &argn) { auto val = map->remove(atoll(argv[argn++])); if (val) { std::cout << *val << std::endl; delete val; } else { std::cout << "Entry not found\n"; } } /* * remove -- (internal) remove specialization for persistent ctree */ template <> void remove>(pool_base pop, persistent_ptr &map, char *argv[], int &argn) { auto val = map->remove(atoll(argv[argn++])); if (val) { std::cout << *val << std::endl; transaction::exec_tx(pop, [&] { delete_persistent(val); }); } else { std::cout << "Entry not found\n"; } } /* * insert -- (internal) insert specialization for persistent ctree */ template <> void insert>(pool_base pop, persistent_ptr &map, char *argv[], int &argn) { transaction::exec_tx(pop, [&] { map->insert(atoll(argv[argn]), make_persistent(atoll(argv[argn + 1]))); }); argn += 2; } /* * exec_op -- (internal) execute single operation */ template void exec_op(pool_base pop, T &map, queue_op op, char *argv[], int &argn) { switch (op) { case MAP_INSERT_NEW: map->insert_new(atoll(argv[argn]), atoll(argv[argn + 1])); argn += 2; break; case MAP_INSERT: insert(pop, map, argv, argn); break; case MAP_GET: { auto val = map->get(atoll(argv[argn])); if (val) std::cout << *val << std::endl; else std::cout << "key not found\n"; break; } case MAP_REMOVE: remove(pop, map, argv, argn); break; case MAP_REMOVE_FREE: map->remove_free(atoll(argv[4])); break; case MAP_CLEAR: map->clear(); break; case MAP_PRINT: map->foreach (printer, 0); break; default: throw std::invalid_argument("invalid queue operation"); } } } int main(int argc, char *argv[]) { if (argc < 4) { std::cerr << "usage: " << argv[0] << " file-name " "[insert|insert_new " "|get |remove | remove_free " "]" << std::endl; return 1; } std::string path = argv[1]; std::string type = argv[2]; pool pop; try { if (file_exists(path.c_str()) != 0) { pop = pool::create(path, LAYOUT, PMEMOBJ_MIN_POOL, CREATE_MODE_RW); } else { pop = pool::open(path, LAYOUT); } } catch (pmem::pool_error &e) { std::cerr << e.what() << std::endl; return 1; } persistent_ptr q; try { q = pop.get_root(); } catch (std::exception &e) { std::cerr << e.what() << std::endl; pop.close(); return 1; } if (!q->ptree) { try { transaction::exec_tx(pop, [&] { q->ptree = make_persistent(); }); } catch (pmem::transaction_error &e) { std::cerr << e.what() << std::endl; pop.close(); return 1; } } auto vtree = std::make_shared(); for (int i = 3; i < argc;) { queue_op op = parse_queue_op(argv[i++]); try { if (type == "volatile") exec_op(pop, vtree, op, argv, i); else exec_op(pop, q->ptree, op, argv, i); } catch (std::exception &e) { std::cerr << e.what() << std::endl; break; } } pop.close(); return 0; } pmdk-1.4.1/src/examples/libpmemobj++/map_cli/map_cli.vcxproj000066400000000000000000000054771331545616200237730ustar00rootroot00000000000000 Debug x64 Release x64 {9D1C3F29-1268-4241-BEFB-89D2859C62D3} pmemobj_cpp 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true .;$(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest CompileAsCpp pmdk-1.4.1/src/examples/libpmemobj++/map_cli/map_cli.vcxproj.filters000066400000000000000000000014261331545616200254300ustar00rootroot00000000000000 {18ad259a-a231-4ac5-95b1-42c10fc3df57} {cd05d003-c025-4e56-92d4-592230215034} Source Files Header Files Header Files pmdk-1.4.1/src/examples/libpmemobj++/panaconda/000077500000000000000000000000001331545616200212555ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/panaconda/.gitignore000066400000000000000000000000121331545616200232360ustar00rootroot00000000000000panaconda pmdk-1.4.1/src/examples/libpmemobj++/panaconda/Makefile000066400000000000000000000042011331545616200227120ustar00rootroot00000000000000# # Copyright 2016-2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemobj/panaconda/Makefile -- build panaconda # TOP := $(dir $(lastword $(MAKEFILE_LIST)))../../../../ include $(TOP)/src/common.inc NCURSES := $(call check_package, ncurses) ifeq ($(NCURSES),y) PROGS = panaconda else $(info NOTE: Skipping panaconda because ncurses is missing \ -- see src/examples/libpmemobj/panaconda/README for details.) endif LIBS = -lpmemobj -lpmem -pthread ifeq ($(shell uname -s),FreeBSD) LIBS += -lc endif ifeq ($(NCURSES),y) LIBS += $(shell $(PKG_CONFIG) --libs ncurses) endif COMPILE_LANG = cpp include ../../Makefile.inc INCS += -I../ panaconda: panaconda.o pmdk-1.4.1/src/examples/libpmemobj++/panaconda/README000066400000000000000000000021571331545616200221420ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemobj++/panconda/README. This directory contains an example application implemented using libpmemobj, it's a game in which all the objects are stored on persistent memory. This means that the game process can be safely killed and then resumed. To launch the game: ./panaconda /path/game/session/file or ./panaconda /path/game/session/file -m /path/config/file/conf/cfg The second option allow you to define your own maze. Meaning of symbols in config file is given below: '1' - wall '0' - space conf.cfg contains example of predefined maze. The file with the game session will either be created if it doesn't exist or opened if it contains a valid pool. Controls: move - arrow keys quit - 'q' new game - 'n' This game demonstrates the usage of the very basics of the libpmemobj C++ bindings. It demonstrates pool management, persistent pointers and transactions. ** DEPENDENCIES: ** In order to build the game you need to install ncurses development package. rpm-based systems : ncurses-devel dpkg-based systems: libncursesX-dev (where X is the API/ABI version) pmdk-1.4.1/src/examples/libpmemobj++/panaconda/conf.cfg000066400000000000000000000017351331545616200226710ustar00rootroot0000000000000011111111111111111111111111111111 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000111000000000111000000001 10000000111000010000111000000001 10000000000000111000000000000001 10000000000001111100000000000001 10000000000000000000000000000001 10000011111111111111111111000001 10000000011111111111111000000001 10000000000000111100000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 11111111111111111111111111111111pmdk-1.4.1/src/examples/libpmemobj++/panaconda/panaconda.cpp000066400000000000000000000504411331545616200237110ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * panaconda.cpp -- example usage of libpmemobj C++ bindings */ #ifdef __FreeBSD__ #define _WITH_GETLINE #endif #include #include #include #include #include #ifdef __FreeBSD__ #include /* Need pkg, not system, version */ #else #include #endif #include #include "panaconda.hpp" #define LAYOUT_NAME "panaconda" #define DEFAULT_DELAY 120000 #define SNAKE_START_POS_X 5 #define SNAKE_START_POS_Y 5 #define SNAKE_START_DIR (direction::RIGHT) #define SNAKE_STAR_SEG_NO 5 #define BOARD_STATIC_SIZE_ROW 40 #define BOARD_STATIC_SIZE_COL 30 #define PLAYER_POINTS_PER_HIT 10 using pmem::transaction_error; using pmem::transaction_scope_error; using pmem::pool_error; using pmem::obj::transaction; using pmem::obj::persistent_ptr; using pmem::obj::pool; using pmem::obj::make_persistent; using pmem::obj::delete_persistent; using examples::list; /* * Color_pair */ color_pair::color_pair() : color_bg(COLOR_BLACK), color_fg(COLOR_BLACK) { } color_pair::color_pair(const int col_fg, const int col_bg) : color_bg(col_bg), color_fg(col_fg) { } /* * Helper */ struct color_pair helper::get_color(const object_type obj_type) { struct color_pair res; switch (obj_type) { case SNAKE_SEGMENT: res = color_pair(COLOR_WHITE, COLOR_BLACK); break; case WALL: res = color_pair(COLOR_BLUE, COLOR_BLUE); break; case FOOD: res = color_pair(COLOR_RED, COLOR_BLACK); break; default: std::cout << "Error: get_color - wrong value passed!" << std::endl; assert(0); } return res; } int helper::parse_params(int argc, char *argv[], struct parameters *par) { int opt; std::string app = argv[0]; while ((opt = getopt(argc, argv, "m:")) != -1) { switch (opt) { case 'm': par->use_maze = true; par->maze_path = optarg; break; default: helper::print_usage(app); return -1; } } if (optind < argc) { par->name = argv[optind]; } else { helper::print_usage(app); return -1; } return 0; } inline void helper::sleep(int time) { clock_t curr_time = clock(); while (clock() < (curr_time + time)) { } } inline void helper::print_usage(std::string &name) { std::cout << "Usage: " << name << " [-m ] \n"; } /* * Point */ point::point() : x(0), y(0) { } point::point(int x, int y) : x(x), y(y) { } bool operator==(point &point1, point &point2) { return point1.x == point2.x && point1.y == point2.y; } /* * Shape */ element_shape::element_shape(int shape) { int n_curves_symbol = get_symbol(shape); val = COLOR_PAIR(shape) | n_curves_symbol; } int element_shape::get_val() { return val; } int element_shape::get_symbol(int shape) { int symbol = 0; switch (shape) { case SNAKE_SEGMENT: symbol = ACS_DIAMOND; break; case WALL: symbol = ACS_BLOCK; break; case FOOD: symbol = ACS_CKBOARD; break; default: symbol = ACS_DIAMOND; break; } return symbol; } /* * Element */ board_element::board_element() : position(make_persistent(0, 0)), shape(make_persistent(SNAKE_SEGMENT)), element_dir(direction::LEFT) { } board_element::board_element(int px, int py, pmem::obj::persistent_ptr shape, direction dir) : position(make_persistent(px, py)), shape(shape), element_dir(dir) { } board_element::board_element(point p, pmem::obj::persistent_ptr shape, direction dir) : position(make_persistent(p.x, p.y)), shape(shape), element_dir(dir) { } board_element::board_element(const board_element &element) : position( make_persistent(element.position->x, element.position->y)), shape(element.shape), element_dir(UNDEFINED) { } board_element::~board_element() { pmem::obj::delete_persistent(position); position = nullptr; pmem::obj::delete_persistent(shape); shape = nullptr; } persistent_ptr board_element::calc_new_position(const direction dir) { persistent_ptr pt = make_persistent(position->x, position->y); switch (dir) { case direction::DOWN: pt->y = pt->y + 1; break; case direction::LEFT: pt->x = pt->x - 1; break; case direction::RIGHT: pt->x = pt->x + 1; break; case direction::UP: pt->y = pt->y - 1; break; default: break; } return pt; } void board_element::set_position(const persistent_ptr new_point) { position = new_point; } persistent_ptr board_element::get_position(void) { return position; } void board_element::print(void) { mvaddch(position->y, position->x, shape->get_val()); } void board_element::print_double_col(void) { mvaddch(position->y, (2 * position->x), shape->get_val()); } void board_element::print_single_double_col(void) { mvaddch(position->y, (2 * position->x), shape->get_val()); mvaddch(position->y, (2 * position->x - 1), shape->get_val()); } direction board_element::get_direction(void) { return element_dir; } void board_element::set_direction(const direction dir) { element_dir = dir; } /* * Snake */ snake::snake() { snake_segments = make_persistent>(); for (unsigned i = 0; i < SNAKE_STAR_SEG_NO; ++i) { persistent_ptr shape = make_persistent(SNAKE_SEGMENT); persistent_ptr element = make_persistent(SNAKE_START_POS_X - i, SNAKE_START_POS_Y, shape, SNAKE_START_DIR); snake_segments->push_back(element); } last_seg_position = point(); last_seg_dir = direction::RIGHT; } snake::~snake() { snake_segments->clear(); delete_persistent>(snake_segments); } void snake::move(const direction dir) { int snake_size = snake_segments->size(); persistent_ptr new_position_point; last_seg_position = *(snake_segments->get(snake_size - 1)->get_position().get()); last_seg_dir = snake_segments->get(snake_size - 1)->get_direction(); for (int i = (snake_size - 1); i >= 0; --i) { if (i == 0) { new_position_point = snake_segments->get(i)->calc_new_position(dir); snake_segments->get(i)->set_direction(dir); } else { new_position_point = snake_segments->get(i)->calc_new_position( snake_segments->get(i - 1) ->get_direction()); snake_segments->get(i)->set_direction( snake_segments->get(i - 1)->get_direction()); } snake_segments->get(i)->set_position(new_position_point); } } void snake::print(void) { int i = 0; persistent_ptr segp; while ((segp = snake_segments->get(i++)) != nullptr) segp->print_double_col(); } void snake::add_segment(void) { persistent_ptr shape = make_persistent(SNAKE_SEGMENT); persistent_ptr segp = make_persistent( last_seg_position, shape, last_seg_dir); snake_segments->push_back(segp); } bool snake::check_point_against_segments(point point) { int i = 0; bool result = false; persistent_ptr segp; while ((segp = snake_segments->get(i++)) != nullptr) { if (point == *(segp->get_position().get())) { result = true; break; } } return result; } point snake::get_head_point(void) { return *(snake_segments->get(0)->get_position().get()); } direction snake::get_direction(void) { return snake_segments->get(0)->get_direction(); } point snake::get_next_point(const direction dir) { return *(snake_segments->get(0)->calc_new_position(dir).get()); } /* * Board */ game_board::game_board() { persistent_ptr shape = make_persistent(FOOD); food = make_persistent(0, 0, shape, direction::UNDEFINED); layout = make_persistent>(); anaconda = make_persistent(); size_row = 20; size_col = 20; } game_board::~game_board() { layout->clear(); delete_persistent>(layout); delete_persistent(anaconda); delete_persistent(food); } void game_board::print(const int score) { const int offset_y = 2 * size_col + 5; const int offset_x = 2; int i = 0; persistent_ptr elmp; while ((elmp = layout->get(i++)) != nullptr) elmp->print_single_double_col(); anaconda->print(); food->print_double_col(); mvprintw((offset_x + 0), offset_y, " ##### panaconda ##### "); mvprintw((offset_x + 1), offset_y, " # # "); mvprintw((offset_x + 2), offset_y, " # q - quit # "); mvprintw((offset_x + 3), offset_y, " # n - new game # "); mvprintw((offset_x + 4), offset_y, " # # "); mvprintw((offset_x + 5), offset_y, " ##################### "); mvprintw((offset_x + 7), offset_y, " Score: %d ", score); } void game_board::print_game_over(const int score) { int x = size_col / 3; int y = size_row / 6; mvprintw(y + 0, x, "####### ####### # # #######"); mvprintw(y + 1, x, "# # # ## ## # "); mvprintw(y + 2, x, "# ### ####### # # # # #### "); mvprintw(y + 3, x, "# # # # # # # # "); mvprintw(y + 4, x, "####### # # # # #######"); mvprintw(y + 6, x, "####### # # ####### #######"); mvprintw(y + 7, x, "# # # # # # #"); mvprintw(y + 8, x, "# # # # #### #######"); mvprintw(y + 9, x, "# # # # # # # "); mvprintw(y + 10, x, "####### # ####### # #"); mvprintw(y + 12, x, " Last score: %d ", score); mvprintw(y + 14, x, " q - quit"); mvprintw(y + 15, x, " n - new game"); } int game_board::creat_dynamic_layout(const unsigned row_no, char *const buffer) { persistent_ptr element; persistent_ptr shape; for (unsigned i = 0; i < size_col; ++i) { if (buffer[i] == config_file_symbol::SYM_WALL) { shape = make_persistent(WALL); element = element = make_persistent( i, row_no, shape, direction::UNDEFINED); layout->push_back(element); } } return 0; } int game_board::creat_static_layout(void) { persistent_ptr element; persistent_ptr shape; size_row = BOARD_STATIC_SIZE_ROW; size_col = BOARD_STATIC_SIZE_COL; // first and last row for (unsigned i = 0; i < size_col; ++i) { shape = make_persistent(WALL); element = make_persistent(i, 0, shape, direction::UNDEFINED); layout->push_back(element); shape = make_persistent(WALL); element = make_persistent( i, (size_row - 1), shape, direction::UNDEFINED); layout->push_back(element); } // middle rows for (unsigned i = 1; i < size_row; ++i) { shape = make_persistent(WALL); element = make_persistent(0, i, shape, direction::UNDEFINED); layout->push_back(element); shape = make_persistent(WALL); element = make_persistent( (size_col - 1), i, shape, direction::UNDEFINED); layout->push_back(element); } return 0; } bool game_board::is_snake_collision(point point) { return anaconda->check_point_against_segments(point); } bool game_board::is_wall_collision(point point) { int i = 0; bool result = false; persistent_ptr wallp; while ((wallp = layout->get(i++)) != nullptr) { if (point == *(wallp->get_position().get())) { result = true; break; } } return result; } bool game_board::is_collision(point point) { return is_snake_collision(point) || is_wall_collision(point); } bool game_board::is_snake_head_food_hit(void) { bool result = false; point head_point = anaconda->get_head_point(); if (head_point == *(food->get_position().get())) { result = true; } return result; } void game_board::set_new_food(const point point) { persistent_ptr shape = make_persistent(FOOD); delete_persistent(food); food = make_persistent(point, shape, direction::UNDEFINED); } void game_board::create_new_food(void) { const int max_repeat = 50; int count = 0; int rand_row = 0; int rand_col = 0; while (count < max_repeat) { rand_row = 1 + rand() % (get_size_row() - 2); rand_col = 1 + rand() % (get_size_col() - 2); point food_point(rand_col, rand_row); if (!is_collision(food_point)) { set_new_food(food_point); break; } count++; } } snake_event game_board::move_snake(const direction dir) { snake_event event = snake_event::EV_OK; point next_pt = anaconda->get_next_point(dir); if (is_collision(next_pt)) { event = snake_event::EV_COLLISION; } else { anaconda->move(dir); } return event; } void game_board::add_snake_segment(void) { anaconda->add_segment(); } unsigned game_board::get_size_row(void) { return size_row; } void game_board::set_size_row(const unsigned size_r) { size_row = size_r; } unsigned game_board::get_size_col(void) { return size_col; } void game_board::set_size_col(const unsigned size_c) { size_col = size_c; } direction game_board::get_snake_dir(void) { return anaconda->get_direction(); } /* * Game_state */ game_state::game_state() { } game_state::~game_state() { } pmem::obj::persistent_ptr game_state::get_board() { return board; } pmem::obj::persistent_ptr game_state::get_player() { return player; } void game_state::init(void) { board = make_persistent(); player = make_persistent(); } void game_state::clean_pool(void) { delete_persistent(board); board = nullptr; delete_persistent(player); player = nullptr; } /* * Player */ game_player::game_player() : score(0), state(STATE_PLAY) { } game_player::~game_player() { } int game_player::get_score(void) { return score; } play_state game_player::get_state(void) { return state; } void game_player::set_state(const play_state st) { state = st; } void game_player::update_score(void) { score = score + PLAYER_POINTS_PER_HIT; } /* * Game */ game::game(struct parameters *par) { pool pop; initscr(); start_color(); nodelay(stdscr, true); curs_set(0); keypad(stdscr, true); params = par; if (pool::check(params->name, LAYOUT_NAME) == 1) pop = pool::open(params->name, LAYOUT_NAME); else pop = pool::create(params->name, LAYOUT_NAME, PMEMOBJ_MIN_POOL * 10, 0666); state = pop; direction_key = direction::UNDEFINED; last_key = KEY_CLEAR; delay = DEFAULT_DELAY; init_colors(); srand(time(0)); } game::~game() { } void game::init_colors(void) { struct color_pair color_pair = helper::get_color(SNAKE_SEGMENT); init_pair(SNAKE_SEGMENT, color_pair.color_fg, color_pair.color_bg); color_pair = helper::get_color(WALL); init_pair(WALL, color_pair.color_fg, color_pair.color_bg); color_pair = helper::get_color(FOOD); init_pair(FOOD, color_pair.color_fg, color_pair.color_bg); } void game::init(void) { int ret = 0; persistent_ptr r = state.get_root(); if (r->get_board() == nullptr) { transaction::exec_tx(state, [&r, &ret, this]() { r->init(); if (params->use_maze) ret = parse_conf_create_dynamic_layout(); else ret = r->get_board()->creat_static_layout(); r->get_board()->create_new_food(); }); if (ret) { clean_pool(); clear_prog(); throw std::runtime_error("Error: Config file error!"); } } direction_key = r->get_board()->get_snake_dir(); } void game::process_step(void) { snake_event ret_event = EV_OK; persistent_ptr r = state.get_root(); transaction::exec_tx(state, [&]() { ret_event = r->get_board()->move_snake(direction_key); if (EV_COLLISION == ret_event) { r->get_player()->set_state(play_state::STATE_GAMEOVER); return; } else { if (r->get_board()->is_snake_head_food_hit()) { r->get_board()->create_new_food(); r->get_board()->add_snake_segment(); r->get_player()->update_score(); } } }); r->get_board()->print(r->get_player()->get_score()); } inline bool game::is_stopped(void) { return action::ACTION_QUIT == last_key; } void game::set_direction_key(void) { switch (last_key) { case KEY_LEFT: if (direction::RIGHT != direction_key) direction_key = direction::LEFT; break; case KEY_RIGHT: if (direction::LEFT != direction_key) direction_key = direction::RIGHT; break; case KEY_UP: if (direction::DOWN != direction_key) direction_key = direction::UP; break; case KEY_DOWN: if (direction::UP != direction_key) direction_key = direction::DOWN; break; default: break; } } void game::process_key(const int lastkey) { last_key = lastkey; set_direction_key(); if (action::ACTION_NEW_GAME == last_key) { clean_pool(); init(); } } void game::clean_pool(void) { persistent_ptr r = state.get_root(); transaction::exec_tx(state, [&]() { r->clean_pool(); }); } void game::process_delay(void) { helper::sleep(delay); } void game::clear_screen(void) { erase(); } void game::game_over(void) { persistent_ptr r = state.get_root(); r->get_board()->print_game_over(r->get_player()->get_score()); } bool game::is_game_over(void) { persistent_ptr r = state.get_root(); return (r->get_player()->get_state() == play_state::STATE_GAMEOVER); } void game::clear_prog(void) { state.close(); endwin(); } int game::parse_conf_create_dynamic_layout(void) { FILE *cfg_file; char *line = NULL; size_t len = 0; unsigned i = 0; ssize_t col_no = 0; cfg_file = fopen(params->maze_path.c_str(), "r"); if (cfg_file == NULL) return -1; persistent_ptr r = state.get_root(); while ((col_no = getline(&line, &len, cfg_file)) != -1) { if (i == 0) r->get_board()->set_size_col(col_no - 1); try { transaction::exec_tx(state, [&]() { r->get_board()->creat_dynamic_layout(i, line); }); } catch (transaction_error &err) { std::cout << err.what() << std::endl; } catch (transaction_scope_error &tse) { std::cout << tse.what() << std::endl; } i++; } r->get_board()->set_size_row(i); free(line); fclose(cfg_file); return 0; } /* * main */ int main(int argc, char *argv[]) { struct parameters params; params.use_maze = false; if (helper::parse_params(argc, argv, ¶ms)) return -1; int ret = -1; try { std::unique_ptr snake_game{new game(¶ms)}; snake_game->init(); while (!snake_game->is_stopped()) { int input = getch(); snake_game->process_key(input); if (snake_game->is_game_over()) { snake_game->game_over(); } else { snake_game->process_delay(); snake_game->clear_screen(); snake_game->process_step(); } } snake_game->clear_prog(); ret = 0; } catch (transaction_error &err) { std::cout << err.what() << std::endl; } catch (transaction_scope_error &tse) { std::cout << tse.what() << std::endl; } catch (pool_error &pe) { std::cout << pe.what() << std::endl; } catch (std::logic_error &le) { std::cout << le.what() << std::endl; } catch (std::runtime_error &re) { std::cout << re.what() << std::endl; } return ret; } pmdk-1.4.1/src/examples/libpmemobj++/panaconda/panaconda.hpp000066400000000000000000000144171331545616200237210ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * panaconda.hpp -- example usage of libpmemobj C++ bindings */ #ifndef PANACONDA_HPP #define PANACONDA_HPP #include #include #include #include #include "list.hpp" class board_element; enum direction { UNDEFINED, DOWN, RIGHT, UP, LEFT }; enum object_type { SNAKE_SEGMENT, WALL, FOOD }; enum config_file_symbol { SYM_NOTHING = '0', SYM_WALL = '1' }; enum play_state { STATE_NEW, STATE_PLAY, STATE_GAMEOVER }; enum snake_event { EV_OK, EV_COLLISION }; enum action { ACTION_NEW_GAME = 'n', ACTION_QUIT = 'q' }; typedef pmem::obj::persistent_ptr> element_list; struct color_pair { color_pair(); color_pair(const int col_fg, const int col_bg); int color_bg; int color_fg; }; struct parameters { bool use_maze; std::string name; std::string maze_path; }; class helper { public: static color_pair get_color(const object_type obj_type); static int parse_params(int argc, char *argv[], struct parameters *params); static inline void sleep(int time); static inline void print_usage(std::string &name); }; class point { public: pmem::obj::p x; pmem::obj::p y; point(); point(int x, int y); friend bool operator==(point &point1, point &point2); }; bool operator==(point &point1, point &point2); class element_shape { public: element_shape() = default; element_shape(int shape); int get_val(); private: pmem::obj::p val; int get_symbol(int shape); }; class board_element { public: board_element(); board_element(int px, int py, pmem::obj::persistent_ptr shape, direction dir); board_element(point p, pmem::obj::persistent_ptr shape, direction dir); board_element(const board_element &element); ~board_element(); pmem::obj::persistent_ptr calc_new_position(const direction dir); void print(void); void print_double_col(void); void print_single_double_col(void); pmem::obj::persistent_ptr get_position(void); void set_position(const pmem::obj::persistent_ptr new_point); direction get_direction(void); void set_direction(const direction dir); private: pmem::obj::persistent_ptr position; pmem::obj::persistent_ptr shape; pmem::obj::p element_dir; }; class snake { public: snake(); ~snake(); void move(const direction dir); void print(void); void add_segment(void); bool check_point_against_segments(point point); point get_head_point(void); direction get_direction(void); point get_next_point(const direction dir); private: element_list snake_segments; pmem::obj::p last_seg_position; pmem::obj::p last_seg_dir; }; class game_board { public: game_board(); ~game_board(); void print(const int score); void print_game_over(const int score); unsigned get_size_row(void); void set_size_row(const unsigned size_r); unsigned get_size_col(void); void set_size_col(const unsigned size_c); int creat_dynamic_layout(const unsigned row_no, char *const buffer); int creat_static_layout(void); bool is_snake_head_food_hit(void); void create_new_food(void); bool is_collision(point point); snake_event move_snake(const direction dir); direction get_snake_dir(void); void add_snake_segment(void); private: pmem::obj::persistent_ptr anaconda; pmem::obj::persistent_ptr food; element_list layout; pmem::obj::p size_row; pmem::obj::p size_col; void set_new_food(const point point); bool is_snake_collision(point point); bool is_wall_collision(point point); }; class game_player { public: game_player(); ~game_player(); int get_score(void); void update_score(void); play_state get_state(void); void set_state(const play_state st); private: pmem::obj::p score; pmem::obj::p state; }; class game_state { public: game_state(); ~game_state(); pmem::obj::persistent_ptr get_board(); pmem::obj::persistent_ptr get_player(); void init(void); void clean_pool(void); private: pmem::obj::persistent_ptr board; pmem::obj::persistent_ptr player; }; class game { public: game(struct parameters *par); ~game(); void init(void); void init_colors(void); void process_step(void); void process_key(const int lastkey); inline bool is_stopped(void); void process_delay(void); void clear_screen(void); bool is_game_over(void); void game_over(void); void clear_prog(void); private: pmem::obj::pool state; int last_key; int delay; struct parameters *params; direction direction_key; void clean_pool(void); void set_direction_key(void); int parse_conf_create_dynamic_layout(void); }; #endif /* PANACONDA_HPP */ pmdk-1.4.1/src/examples/libpmemobj++/pman/000077500000000000000000000000001331545616200202645ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/pman/.gitignore000066400000000000000000000000051331545616200222470ustar00rootroot00000000000000pman pmdk-1.4.1/src/examples/libpmemobj++/pman/Makefile000066400000000000000000000037571331545616200217400ustar00rootroot00000000000000# # Copyright 2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # TOP := $(dir $(lastword $(MAKEFILE_LIST)))../../../../ include $(TOP)/src/common.inc NCURSES := $(call check_package, ncurses) ifeq ($(NCURSES),y) PROGS = pman else $(info NOTE: Skipping pman because ncurses is missing \ -- see src/examples/libpmemobj/pman/README for details.) endif LIBS = -lpmemobj -lpmem -pthread ifeq ($(NCURSES),y) LIBS += $(shell $(PKG_CONFIG) --libs ncurses) endif COMPILE_LANG = cpp include ../../Makefile.inc INCS += -I../ pman: pman.o pmdk-1.4.1/src/examples/libpmemobj++/pman/README000066400000000000000000000016251331545616200211500ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemobj++/pman/README. This directory contains an example application implemented using libpmemobj, it's a game in which all the objects are stored on persistent memory. This means that the game process can be safely killed and then resumed. To launch the game: ./pman [map file] The file with the game session will either be created if it doesn't exist or opened if it contains a valid pool. Controls: move - arrow keys, jkli place bomb - spacebar, b quit - 'q' resume - 'r' This game demonstrates the usage of the very basics of the libpmemobj C++ bindings. It demonstrates pool management, persistent pointers and transactions. ** DEPENDENCIES: ** In order to build the game you need to install ncurses development package. rpm-based systems : ncurses-devel dpkg-based systems: libncursesX-dev (where X is the API/ABI version) pmdk-1.4.1/src/examples/libpmemobj++/pman/map000066400000000000000000000031501331545616200207630ustar00rootroot00000000000000######################################## # # ## # # # # ############ # ## # ############ # # # # # # ## # # # # # # ###### # # ###### # # # # # # # # ## # # # # # # ##### #### ## #### ##### # # # # # ## # # # # # # # ############ ############ # # # # # # # # # # # # # # # ######## ###### ######## # # # # # # # ####### ### ########### ### ######## # # # ## # # # ####### ######## ## ####### ######## # # # ## # # # # ############ # ## # ############ # # # # # # # # # ########## ##### #### ########## # # # # # # . # # # # # # # # # # # # # ########## ########## ########## # # # # # # # # # ############ # ## # ############ # # # # ## # # # ####### ######## ## ####### ######## # # # ## # # # ####### ### ########### ### ######## # # # # # # # ######## ###### ######## # # # # # # # # # # # # # # # ############ ############ # # # # # # # ## # # # # # ##### #### ## #### ##### # # # # # # # ## # # # # # # # ###### # # ###### # # # # # # ## # # # # # # ############ # ## # ############ # # # # ## # # ######################################## pmdk-1.4.1/src/examples/libpmemobj++/pman/pman.cpp000066400000000000000000000630461331545616200217340ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * pman.cpp -- example usage of libpmemobj C++ bindings */ #include "list.hpp" #include #include #include #include #include #ifdef __FreeBSD__ #include /* Need pkg, not system, version */ #else #include #endif #define LAYOUT_NAME "pman" #define SIZE 40 #define MAX_SIZE 38 #define MAX_BOMBS 5 #define KEY_SPACE 32 #define RAND_FIELD() (rand() % (SIZE - 2) + 1) #define EXPLOSION_TIME 20 #define EXPLOSION_COUNTER 80 #define SLEEP_TIME (2 * CLOCKS_PER_SEC) #define GAME_DELAY 40000 #define SLEEP(t) \ do { \ struct timespec req = {0, t * 1000}; \ while (nanosleep(&req, &req) == -1 && errno == EINTR) \ ; \ } while (0) using pmem::obj::p; using pmem::obj::persistent_ptr; using pmem::obj::pool; using pmem::obj::pool_base; using pmem::obj::make_persistent; using pmem::obj::delete_persistent; using pmem::obj::transaction; namespace examples { class state; } /* namespace examples */ namespace { pool pop; } namespace examples { enum position { UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT, POS_MIDDLE, POS_MAX, }; enum direction { DOWN, RIGHT, UP, LEFT, STOP, }; enum field { FREE, FOOD, WALL, PLAYER, ALIEN, EXPLOSION, BONUS, LIFE, BOMB, }; class point { public: point() = default; point(int xf, int yf); point(position cor); void move_back(); void move_home(); /* x component of object's position */ p x; /* y component of object's position */ p y; /* x component of object's previous position */ p prev_x; /* y component of object's previous position */ p prev_y; /* type of field of object */ p cur_field; /* type of field where object stood before */ p prev_field; protected: void move(); /* direction in which object is moving */ p dir; private: /* starting position of the object */ p home; }; class bomb : public point { public: bomb(int xf, int yf); void progress(); void explosion(); void print_time(); /* flag determining is bomb exploded */ p exploded; /* flag determining is bomb used */ p used; private: /* counter determining where change of bomb state is necessary*/ p timer; }; typedef persistent_ptr> bomb_vec; class player : public point { public: player(position cor); void progress(int in, bomb_vec *bombs); }; class alien : public point { public: alien(position cor); void progress(); void move_back_alien(); private: p rand_pos; }; class intro : public point { public: intro(int x, int y, direction d); void progress(); private: /* random color in which object will be displayed*/ p color; /* number determining object's path on the board*/ p num; }; class board_state { public: board_state(const std::string &map_file); ~board_state(); void reset_params(); void reset_board(); void print(unsigned hs); void reset(); void dead(); bool is_free(int x, int y); void set_board_elm(persistent_ptr p); void add_points(int x, int y); bool is_last_alien_killed(int x, int y); void set_explosion(int x, int y, field f); void explosion(int x, int y, field f); inline field get_board_elm(int x, int y) { return board[y * SIZE + x]; } inline void set_board_elm(int x, int y, field f) { board[y * SIZE + x] = f; } p level; /* number of level */ p timer; /* measure time since game start */ p n_aliens; /* number of not killed aliens */ p highscore; /* score of the best game */ p score; /* current score */ p game_over; /* set true if game is over */ private: int shape(field f); void set_bonus(field f); void set_board(const std::string &map_file); int find_wall(int x, int y, direction dir); p life; /* number of lives left for player */ persistent_ptr board; /* current state of board */ persistent_ptr board_tmpl; /* board template loaded from file*/ }; class state { public: state(); bool init(const std::string &map_file); void game(); private: bool intro_loop(); void print_start(); void print_game_over(); void new_game(const std::string &map_file); void reset_game(); void resume(); void one_move(int in); void collision(); void reset(); void next_level(); void reset_bombs(); bool is_collision(persistent_ptr p1, persistent_ptr p2); /* pointer to player type object */ persistent_ptr pl; /* pointer to board state */ persistent_ptr board; /* pointer to vector of alien type objects */ persistent_ptr> aliens; /* pointer to vector of intro type objects */ persistent_ptr> intro_p; /* pointer to vector of bomb type objects */ bomb_vec bombs; /* the best score player has ever achieved */ p highscore; }; /* * point::point -- overloaded constructor for point class */ point::point(int xf, int yf) : x{xf}, y{yf}, prev_x{xf}, prev_y{yf}, cur_field{FREE}, prev_field{FREE}, dir{DOWN}, home{UP_LEFT} {}; /* * point::point -- overloaded constructor for point class */ point::point(position cor) : x{0}, y{0}, prev_x{0}, prev_y{0}, cur_field{FREE}, prev_field{FREE}, dir{DOWN}, home{cor} { move_home(); } /* * point::move_home -- move object to it's home position */ void point::move_home() { prev_x = x; prev_y = y; switch (home) { case UP_LEFT: x = 1; y = 1; break; case UP_RIGHT: x = MAX_SIZE; y = 1; break; case DOWN_LEFT: x = 1; y = MAX_SIZE; break; case DOWN_RIGHT: x = MAX_SIZE; y = MAX_SIZE; break; case POS_MIDDLE: x = MAX_SIZE / 2; y = MAX_SIZE / 2; break; default: break; } } /* * point::move_back -- move object to it's previous position */ void point::move_back() { x = prev_x; y = prev_y; } /* * point::move -- move object in proper direction */ void point::move() { int tmp_x = 0, tmp_y = 0; switch (dir) { case LEFT: tmp_x = -1; break; case RIGHT: tmp_x = 1; break; case UP: tmp_y = -1; break; case DOWN: tmp_y = 1; break; default: break; } prev_x = x; prev_y = y; x = x + tmp_x; y = y + tmp_y; } /* * intro::intro -- overloaded constructor for intro class */ intro::intro(int x, int y, direction d) : point(x, y) { color = (field)(rand() % BOMB); if (d == DOWN || d == LEFT) num = y; else num = SIZE - y; dir = d; } /* * intro::progress -- perform one move */ void intro::progress() { move(); mvaddch(y, x * 2, COLOR_PAIR(color) | ACS_DIAMOND); int max_size = SIZE - num; if ((x == num && y == num) || (x == num && y == max_size) || (x == max_size && y == num) || (x == max_size && y == max_size)) dir = (direction)((dir + 1) % STOP); } /* * bomb::bomb -- overloaded constructor for bomb class */ bomb::bomb(int xf, int yf) : point(xf, yf) { cur_field = BOMB; exploded = false; used = false; timer = EXPLOSION_COUNTER; } /* * bomb::progress -- checks in which board_state is bomb */ void bomb::progress() { timer = timer - 1; if (exploded == false && timer == 0) explosion(); else if (timer == 0) used = true; } /* * bomb::explosion -- change board_state of bomb on exploded */ void bomb::explosion() { exploded = true; timer = EXPLOSION_TIME; } /* * bomb::print_time -- print time to explosion */ void bomb::print_time() { if (!exploded) mvprintw(y, x * 2, "%u", timer / 10); } /* * player::player -- overloaded constructor for player class */ player::player(position cor) : point(cor) { cur_field = PLAYER; } /* * player::progress -- checks input from keyboard and sets proper direction */ void player::progress(int in, bomb_vec *bombs) { switch (in) { case KEY_LEFT: case 'j': dir = LEFT; break; case KEY_RIGHT: case 'l': dir = RIGHT; break; case KEY_UP: case 'i': dir = UP; break; case KEY_DOWN: case 'k': dir = DOWN; break; case KEY_SPACE: case 'b': dir = STOP; if ((*bombs)->size() <= MAX_BOMBS) (*bombs)->push_back( make_persistent(x, y)); break; } move(); dir = STOP; } /* * alien::alien -- overloaded constructor for alien class */ alien::alien(position cor) : point(cor), rand_pos(false) { cur_field = ALIEN; prev_field = FOOD; } /* * alien::progress -- rand and set direction and move alien */ void alien::progress() { if (rand_pos || rand() % 10 == 0) dir = (direction)(rand() % STOP); rand_pos = false; move(); } /* * alien::move_back_alien -- move alien to previous position */ void alien::move_back_alien() { rand_pos = true; move_back(); } /* * board_state -- constructor for class board_state initializes boards and * needed variables */ board_state::board_state(const std::string &map_file) : highscore(0) { reset_params(); board = make_persistent(SIZE * SIZE); board_tmpl = make_persistent(SIZE * SIZE); for (int i = 0; i < SIZE * SIZE; ++i) set_board_elm(i, 0, FREE); set_board(map_file); } board_state::~board_state() { delete_persistent(board, SIZE * SIZE); delete_persistent(board_tmpl, SIZE * SIZE); } /* board_state::reset_params -- reset game parameters */ void board_state::reset_params() { life = 3; level = 1; n_aliens = 1; score = 0; timer = 0; game_over = false; } /* board_state::reset_board -- reset board state from template */ void board_state::reset_board() { for (auto i = 0; i < SIZE * SIZE; i++) board[i] = board_tmpl[i]; set_bonus(BONUS); set_bonus(LIFE); } /* * board_state::print -- print current board and information about game */ void board_state::print(unsigned hs) { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (get_board_elm(j, i) != FREE) mvaddch(i, j * 2, shape(get_board_elm(j, i))); } } if (score > hs) highscore = score; mvprintw(SIZE + 1, 0, "Score: %d\t\tHighscore: %u\t\tLevel: %u\t" " Timer: %u", (unsigned)score, (unsigned)highscore, (unsigned)level, (unsigned)timer); mvaddch(8, SIZE * 2 + 5, shape(FOOD)); mvprintw(8, SIZE * 2 + 10, " +1 point"); mvaddch(16, SIZE * 2 + 5, shape(BONUS)); mvprintw(16, SIZE * 2 + 10, " +50 point"); mvaddch(24, SIZE * 2 + 5, shape(ALIEN)); mvprintw(24, SIZE * 2 + 10, " +100 point"); mvaddch(32, SIZE * 2 + 5, shape(LIFE)); mvprintw(32, SIZE * 2 + 10, " +1 life"); for (unsigned i = 0; i < life; i++) mvaddch(SIZE + 3, SIZE + life - i * 2, shape(PLAYER)); } /* * board_state::dead -- executed when player lose life */ void board_state::dead() { life = life - 1; if (life <= 0) { game_over = true; } } /* * board_state::reset -- clean board to start new level */ void board_state::reset() { reset_board(); n_aliens = level; timer = 0; } /* * board_state::is_free -- check whether field is free */ bool board_state::is_free(int x, int y) { return !(get_board_elm(x, y) == WALL || get_board_elm(x, y) == BOMB); } /* * board_state::add_points -- check type of field and give proper number of * points */ void board_state::add_points(int x, int y) { switch (get_board_elm(x, y)) { case FOOD: score = score + 1; break; case BONUS: score = score + 50; set_bonus(BONUS); break; case LIFE: if (life < 3) life = life + 1; set_bonus(LIFE); break; default: break; } } /* * board_state::is_last_alien_killed -- remove alien from board and check * whether any other alien stayed on the board */ bool board_state::is_last_alien_killed(int x, int y) { set_board_elm(x, y, FREE); n_aliens = n_aliens - 1; score = score + 100; if (n_aliens != 0) return false; level = level + 1; return true; } /* * board_state::set_board_elm -- set object on its current position on the board * and clean previous position */ void board_state::set_board_elm(persistent_ptr p) { set_board_elm(p->x, p->y, p->cur_field); if (!(p->x == p->prev_x && p->y == p->prev_y)) set_board_elm(p->prev_x, p->prev_y, p->prev_field); } /* * board_state::set_explosion --set exploded fields in proper way */ void board_state::set_explosion(int x, int y, field f) { field prev_f = get_board_elm(x, y); if (prev_f == BONUS || prev_f == LIFE) set_bonus(prev_f); set_board_elm(x, y, f); } /* * board_state::explosion -- mark exploded fields as exploded or free */ void board_state::explosion(int x, int y, field f) { for (int i = find_wall(x, y, UP); i < find_wall(x, y, DOWN); i++) set_explosion(x, i, f); for (int i = find_wall(x, y, LEFT); i < find_wall(x, y, RIGHT); i++) set_explosion(i, y, f); } /* * board_state::shape -- assign proper shape to different types of fields */ int board_state::shape(field f) { int color = COLOR_PAIR(f); if (f == FOOD) return color | ACS_BULLET; else if (f == WALL || f == EXPLOSION) return color | ACS_CKBOARD; else return color | ACS_DIAMOND; } /* * board_state::set_bonus -- find free field and set the bonus there */ void board_state::set_bonus(field f) { int x, y; x = RAND_FIELD(); y = RAND_FIELD(); while (get_board_elm(x, y) != FOOD && get_board_elm(x, y) != FREE) { x = RAND_FIELD(); y = RAND_FIELD(); } set_board_elm(x, y, f); } /* * board_state::set_board -- set board with initial values from file */ void board_state::set_board(const std::string &map_file) { std::ifstream board_file; board_file.open(map_file.c_str()); if (board_file.fail()) assert(0); char num; for (unsigned i = 0; i < SIZE; i++) { for (unsigned j = 0; j < SIZE; j++) { board_file.get(num); if (num == '#') set_board_elm(j, i, WALL); else if (num == ' ') set_board_elm(j, i, FOOD); else set_board_elm(j, i, FREE); } board_file.get(num); } for (auto i = 0; i < SIZE * SIZE; i++) board_tmpl[i] = board[i]; board_file.close(); set_bonus(BONUS); set_bonus(LIFE); } /* * board_state::find_wall -- finds first wall from given point in given * direction */ int board_state::find_wall(int x, int y, direction dir) { switch (dir) { case LEFT: { for (int i = x; i >= 0; i--) { if (get_board_elm(i, y) == WALL) return i + 1; } break; } case RIGHT: { for (int i = x; i <= SIZE; i++) { if (get_board_elm(i, y) == WALL) return i; } break; } case UP: { for (int i = y; i >= 0; i--) { if (get_board_elm(x, i) == WALL) return i + 1; } break; } case DOWN: { for (int i = y; i <= SIZE; i++) { if (get_board_elm(x, i) == WALL) return i; } break; } default: break; } return 0; } /* * state::init -- initialize game */ bool state::init(const std::string &map_file) { int in; if (board == nullptr || pl == nullptr) new_game(map_file); else { while ((in = getch()) != 'y') { mvprintw(SIZE / 4, SIZE / 4, "Do you want to continue the game?" " [y/n]"); if (in == 'n') { resume(); break; } } if (in == 'y' && intro_p->size() == 0) return false; } { transaction::manual tx(pop); if (intro_p->size() == 0) { for (int i = 0; i < SIZE / 4; i++) { intro_p->push_back( make_persistent(i, i, DOWN)); intro_p->push_back(make_persistent( SIZE - i, i, LEFT)); intro_p->push_back(make_persistent( i, SIZE - i, RIGHT)); intro_p->push_back(make_persistent( SIZE - i, SIZE - i, UP)); } } transaction::commit(); } if (intro_loop()) return true; { transaction::manual tx(pop); intro_p->clear(); transaction::commit(); } return false; } /* * state::game -- process game loop */ void state::game() { int in; while ((in = getch()) != 'q') { SLEEP(GAME_DELAY); erase(); if (in == 'r') resume(); if (!board->game_over) one_move(in); else print_game_over(); } } /* * state::intro_loop -- display intro an wait for user's reaction */ bool state::intro_loop() { int in; while ((in = getch()) != 's') { print_start(); unsigned i = 0; persistent_ptr p; { transaction::manual tx(pop); while ((p = intro_p->get(i++)) != nullptr) p->progress(); transaction::commit(); } SLEEP(GAME_DELAY); if (in == 'q') return true; } return false; } /* * state::print_start -- print intro inscription */ void state::print_start() { erase(); int x = SIZE / 1.8; int y = SIZE / 2.5; mvprintw(y + 0, x, "####### # # ####### # #"); mvprintw(y + 1, x, "# # ## ## # # ## #"); mvprintw(y + 2, x, "####### # # # # ####### # # #"); mvprintw(y + 3, x, "# # # # # # # # #"); mvprintw(y + 4, x, "# # # # # # ##"); mvprintw(y + 8, x, " Press 's' to start "); mvprintw(y + 9, x, " Press 'q' to quit "); } /* * state::print_game_over -- print game over inscription */ void state::print_game_over() { erase(); int x = SIZE / 3; int y = SIZE / 6; mvprintw(y + 0, x, "####### ####### # # #######"); mvprintw(y + 1, x, "# # # ## ## # "); mvprintw(y + 2, x, "# ### ####### # # # # #### "); mvprintw(y + 3, x, "# # # # # # # # "); mvprintw(y + 4, x, "####### # # # # #######"); mvprintw(y + 6, x, "####### # # ####### #######"); mvprintw(y + 7, x, "# # # # # # #"); mvprintw(y + 8, x, "# # # # #### #######"); mvprintw(y + 9, x, "# # # # # # # "); mvprintw(y + 10, x, "####### # ####### # #"); mvprintw(y + 13, x, " Your final score is %u ", (unsigned)board->score); if (board->score == highscore) mvprintw(y + 14, x, " YOU BET YOUR BEST SCORE! "); mvprintw(y + 16, x, " Press 'q' to quit "); mvprintw(y + 17, x, " Press 'r' to resume "); } /* * state::new_game -- allocate board_state, player and aliens if root is empty */ void state::new_game(const std::string &map_file) { transaction::manual tx(pop); board = make_persistent(map_file); pl = make_persistent(POS_MIDDLE); intro_p = make_persistent>(); bombs = make_persistent>(); aliens = make_persistent>(); aliens->push_back(make_persistent(UP_LEFT)); transaction::commit(); } /* * state::reset_game -- reset the game from the board template */ void state::reset_game() { transaction::manual tx(pop); board->reset_params(); board->reset_board(); pl = make_persistent(POS_MIDDLE); intro_p = make_persistent>(); bombs = make_persistent>(); aliens = make_persistent>(); aliens->push_back(make_persistent(UP_LEFT)); transaction::commit(); } /* * state::resume -- clean root pointer and start a new game */ void state::resume() { { transaction::manual tx(pop); delete_persistent(pl); pl = nullptr; aliens->clear(); delete_persistent>(aliens); bombs->clear(); delete_persistent>(bombs); intro_p->clear(); delete_persistent>(intro_p); transaction::commit(); } reset_game(); } /* * state::one_move -- process one round where every object moves one time */ void state::one_move(int in) { unsigned i = 0; persistent_ptr a; persistent_ptr b; transaction::manual tx(pop); board->timer = board->timer + 1; pl->progress(in, &bombs); while ((a = aliens->get(i++)) != nullptr) a->progress(); i = 0; while ((b = bombs->get(i++)) != nullptr) { b->progress(); if (b->exploded) board->explosion(b->x, b->y, EXPLOSION); if (b->used) { board->explosion(b->x, b->y, FREE); bombs->erase(--i); } } collision(); board->print(highscore); highscore = board->highscore; i = 0; while ((b = bombs->get(i++)) != nullptr) b->print_time(); transaction::commit(); } /* * state::collision -- check for collisions between any two objects */ void state::collision() { unsigned i = 0; persistent_ptr a; persistent_ptr b; while ((b = bombs->get(i++)) != nullptr) { if (!b->exploded) { if (board->get_board_elm(b->x, b->y) == EXPLOSION) b->explosion(); board->set_board_elm(b); } } i = 0; while ((a = aliens->get(i++)) != nullptr) { if (board->get_board_elm(a->x, a->y) == EXPLOSION) { bool is_over = board->is_last_alien_killed(a->prev_x, a->prev_y); aliens->erase(--i); if (is_over) { if (board->get_board_elm(pl->x, pl->y) == EXPLOSION) board->dead(); next_level(); return; } } } bool dead = false; i = 0; while ((a = aliens->get(i++)) != nullptr) { /*check collision alien with wall or bomb */ if (!board->is_free(a->x, a->y)) a->move_back_alien(); /*check collision alien with player */ if (is_collision(pl, a)) dead = true; /*check collision alien with alien */ unsigned j = 0; persistent_ptr a2; while ((a2 = aliens->get(j++)) != nullptr) { if (a != a2 && is_collision(a, a2)) { a->move_back_alien(); break; } } field prev_f = board->get_board_elm(a->x, a->y); board->set_board_elm(a); if (prev_f != ALIEN && prev_f != PLAYER) a->prev_field = prev_f; } if (!board->is_free(pl->x, pl->y)) pl->move_back(); if (board->get_board_elm(pl->x, pl->y) == EXPLOSION || dead) { board->dead(); reset(); return; } board->add_points(pl->x, pl->y); board->set_board_elm(pl); SLEEP(10000); } /* * state::reset -- move objects on their home positions */ void state::reset() { unsigned i = 0; persistent_ptr a; while ((a = aliens->get(i++)) != nullptr) { a->move_home(); board->set_board_elm(a); } pl->move_back(); pl->move_home(); board->set_board_elm(pl); reset_bombs(); } /* * state::next_level -- clean board, create proper number of aliens and * start new level */ void state::next_level() { reset_bombs(); board->reset(); for (unsigned i = 0; i < board->n_aliens; i++) aliens->push_back(make_persistent( (position)((UP_LEFT + i) % (POS_MAX - 1)))); pl->move_home(); } /* * state::reset_bombs -- remove all bombs */ void state::reset_bombs() { unsigned i = 0; persistent_ptr b; while ((b = bombs->get(i++)) != nullptr) { if (b->exploded) board->explosion(b->x, b->y, FREE); } bombs->clear(); } /* * state::is_collision -- check if there is collision between given objects */ bool state::is_collision(persistent_ptr p1, persistent_ptr p2) { if (p1->x == p2->x && p1->y == p2->y) return true; else if (p1->prev_x == p2->x && p1->prev_y == p2->y && p1->x == p2->prev_x && p1->y == p2->prev_y) return true; return false; } } /* namespace examples */ namespace { void print_usage(const std::string &binary) { std::cout << "Usage:\n" << binary << " [map_file]\n"; } } int main(int argc, char *argv[]) { if (argc < 2 || argc > 3) { print_usage(argv[0]); return 1; } std::string name = argv[1]; std::string map_path = "map"; if (argc == 3) map_path = argv[2]; int ret = -1; try { if (pool::check(name, LAYOUT_NAME) == 1) pop = pool::open(name, LAYOUT_NAME); else pop = pool::create( name, LAYOUT_NAME, PMEMOBJ_MIN_POOL * 2); initscr(); start_color(); init_pair(examples::FOOD, COLOR_YELLOW, COLOR_BLACK); init_pair(examples::WALL, COLOR_WHITE, COLOR_BLACK); init_pair(examples::PLAYER, COLOR_CYAN, COLOR_BLACK); init_pair(examples::ALIEN, COLOR_RED, COLOR_BLACK); init_pair(examples::EXPLOSION, COLOR_CYAN, COLOR_BLACK); init_pair(examples::BONUS, COLOR_YELLOW, COLOR_BLACK); init_pair(examples::LIFE, COLOR_MAGENTA, COLOR_BLACK); nodelay(stdscr, true); curs_set(0); keypad(stdscr, true); persistent_ptr r = pop.get_root(); if ((r != nullptr) && (r->init(map_path) != false)) r->game(); endwin(); pop.close(); ret = 0; } catch (pmem::transaction_error &err) { std::cerr << err.what() << std::endl; } catch (pmem::transaction_scope_error &tse) { std::cerr << tse.what() << std::endl; } catch (pmem::pool_error &pe) { std::cerr << pe.what() << std::endl; } catch (std::logic_error &le) { std::cerr << le.what() << std::endl; } return ret; } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/000077500000000000000000000000001331545616200206315ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/pmpong/.gitignore000066400000000000000000000000421331545616200226150ustar00rootroot00000000000000pmpong fontConf *.dll lib include pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Ball.cpp000066400000000000000000000074711331545616200222200ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Ball.hpp" #include "Pool.hpp" Pool *gamePoolB; Ball::Ball(int x, int y) { this->x = x; this->y = y; velocity = pmem::obj::make_persistent(); this->velocity->x = 0; this->velocity->y = 0; } Ball::~Ball() { pmem::obj::transaction::exec_tx( gamePoolB->getGamePool()->getPoolToTransaction(), [&] { pmem::obj::delete_persistent(velocity); }); } void Ball::move() { setXY(this->x + (int)this->velocity->x, this->y + (int)this->velocity->y); } void Ball::collisionWithWindow() { if (this->y <= SCORE_VIEW_OFFSET + HORIZONAL_LINE_OFFSET || this->y + getBallShape().getRadius() * 2 >= WINDOW_HEIGHT - HORIZONAL_LINE_OFFSET) { setVelocityY(velocity->y * -1); } } void Ball::increaseVelocity() { if (velocity->x < 0) { setVelocityX(velocity->x - BALL_VELOCITY_INCREMENTING); } else { setVelocityX(velocity->x + BALL_VELOCITY_INCREMENTING); } if (velocity->y < 0) { setVelocityY(velocity->y - BALL_VELOCITY_INCREMENTING); } else { setVelocityY(velocity->y + BALL_VELOCITY_INCREMENTING); } } void Ball::setX(int xArg) { pmem::obj::transaction::exec_tx( gamePoolB->getGamePool()->getPoolToTransaction(), [&] { x = xArg; }); } void Ball::setY(int yArg) { pmem::obj::transaction::exec_tx( gamePoolB->getGamePool()->getPoolToTransaction(), [&] { y = yArg; }); } void Ball::setVelocityX(float xArg) { pmem::obj::transaction::exec_tx( gamePoolB->getGamePool()->getPoolToTransaction(), [&] { velocity->x = xArg; }); } void Ball::setVelocityY(float yArg) { pmem::obj::transaction::exec_tx( gamePoolB->getGamePool()->getPoolToTransaction(), [&] { velocity->y = yArg; }); } void Ball::setXY(int xArg, int yArg) { pmem::obj::transaction::exec_tx( gamePoolB->getGamePool()->getPoolToTransaction(), [&] { x = xArg; y = yArg; }); } void Ball::init() { setXY(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); setVelocityX(0); setVelocityY(0); } int Ball::getX() { return this->x; } int Ball::getY() { return this->y; } pmem::obj::persistent_ptr Ball::getVelocity() { return this->velocity; } sf::CircleShape Ball::getBallShape() { sf::CircleShape shapeToRet; shapeToRet.setRadius(BALL_SIZE); shapeToRet.setPosition(sf::Vector2f((float)this->x, (float)this->y)); return shapeToRet; } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Ball.hpp000066400000000000000000000044241331545616200222200ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef BALL_H_ #define BALL_H_ #include "GameConstants.hpp" #include #include #include #include class Ball { public: Ball(int x, int y); ~Ball(); void move(); void collisionWithWindow(); void increaseVelocity(); void setX(int xArg); void setY(int yArg); void setVelocityX(float xArg); void setVelocityY(float yArg); void setXY(int xArg, int yArg); void init(); int getX(); int getY(); pmem::obj::persistent_ptr getVelocity(); sf::CircleShape getBallShape(); private: pmem::obj::p x; pmem::obj::p y; pmem::obj::persistent_ptr velocity; }; #endif /* BALL_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameConstants.hpp000066400000000000000000000056121331545616200241140ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GAMECONSTANTS_H_ #define GAMECONSTANTS_H_ #include #include #include #include #include #include #include #include #define PADDLE_VELOCITY_PLAYER 4 #define PADDLE_VELOCITY_COMPUTER 20 #define WINDOW_HEIGHT 500 #define WINDOW_WIDTH 700 #define BALL_VELOCITY_INCREMENTING 0.2f #define FRAMERATE_LIMIT 70 #define PADDLE_HEIGHT 100 #define PADDLE_WIDTH 12 #define BALL_SIZE 7 #define MENU_ITEMS 4 #define POINTS_TO_WIN 10 #define BALL_PLAYERS_SPEED 4.0f #define BALL_COMPUTER_SPEED 11.0f #define VERTICAL_LINE_OFFSET 15 #define HORIZONAL_LINE_OFFSET 30 #define LINE_THICKNESS 3 #define SCORE_VIEW_OFFSET 20 #define GAME_NAME "pmpong" #define GAMEVIEW_SCORE_FONTSIZE 20 #define MENUVIEW_ITEMS_FONTSIZE 30 #define GAMEOVER_FONTSIZE 45 #define MENUITEM_OFFSET 100 #define GAMOVERVIEW_OFFSET 50 #define LAYOUT_NAME "DEFAULT_LAYOUT_NAME" #define DEFAULT_POOLFILE_NAME "DEFAULT_FILENAME" static inline std::string readFontConf() { static std::string path = ""; std::ifstream file("fontConf"); if (file.is_open()) { getline(file, path); } return path; } #ifndef _WIN32 #define FONT_PATH readFontConf() #else #define FONT_PATH "C:/Windows/Fonts/Arial.ttf" #endif #endif /* GAMECONSTANTS_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameController.cpp000066400000000000000000000154001331545616200242520ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "GameController.hpp" #include "Pool.hpp" Pool *gamePoolG; GameController::GameController() { gameStatus = pmem::obj::make_persistent(); } GameController::~GameController() { pmem::obj::transaction::exec_tx( gamePoolG->getGamePool()->getPoolToTransaction(), [&] { pmem::obj::delete_persistent( gameStatus); }); } void GameController::gameLoop(bool isSimulation) { sf::RenderWindow *gameWindow = new sf::RenderWindow( sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), GAME_NAME); gameWindow->setFramerateLimit(FRAMERATE_LIMIT); sf::Font font; if (!font.loadFromFile(FONT_PATH)) { throw std::runtime_error("Cannot load font from file"); } View *menuView = new MenuView(font); View *gameView = new GameView(font); View *gameOverView = new GameOverView(font); while (gameWindow->isOpen()) { sf::Event event; while (gameWindow->pollEvent(event)) { if (event.type == sf::Event::Closed) gameWindow->close(); } gameWindow->clear(); if (isSimulation) { if (gameStatus->getGameState() != game_state::SIMULATE) { resetGameStatus(); gameStatus->setIsGameToResume(false); gameStatus->setGameState(game_state::SIMULATE); } gameMatchSimulation(gameWindow, gameView, isSimulation); } else { if (gameStatus->getGameState() == game_state::MATCH) { gameMatch(gameWindow, gameView); } else if (gameStatus->getGameState() == game_state::MENU) { menu(gameWindow, menuView); } else if (gameStatus->getGameState() == game_state::SIMULATE) { gameMatchSimulation(gameWindow, gameView, isSimulation); } else if (gameStatus->getGameState() == game_state::GAME_OVER) { gameOver(gameWindow, gameOverView); } } } delete menuView; delete gameView; delete gameOverView; delete gameWindow; } void GameController::gameOver(sf::RenderWindow *gameWindow, View *view) { view->prepareView(*gameStatus); view->displayView(gameWindow); sf::Event event; while (gameWindow->pollEvent(event)) { if (event.type == sf::Event::KeyPressed) { switch (event.key.code) { case sf::Keyboard::Return: gameStatus->setIsGameToResume(false); gameStatus->setGameState( game_state::MENU); break; default: break; } } if (event.type == sf::Event::Closed) gameWindow->close(); } } void GameController::menu(sf::RenderWindow *gameWindow, View *view) { view->prepareView(*gameStatus); view->displayView(gameWindow); sf::Event event; while (gameWindow->pollEvent(event)) { if (event.type == sf::Event::KeyPressed) { handleEventKeypress(event, gameWindow); } if (event.type == sf::Event::Closed) gameWindow->close(); } } void GameController::handleEventKeypress(sf::Event &event, sf::RenderWindow *gameWindow) { switch (event.key.code) { case sf::Keyboard::Up: gameStatus->setMenuItem( gameStatus->getMenuItem() == 0 ? MENU_ITEMS - 1 : gameStatus->getMenuItem() - 1); break; case sf::Keyboard::Down: gameStatus->setMenuItem( (gameStatus->getMenuItem() + 1) % MENU_ITEMS); break; case sf::Keyboard::Return: if (gameStatus->getMenuItem() == NEW_GAME) { resetGameStatus(); gameStatus->setIsGameToResume(true); gameStatus->setGameState(game_state::MATCH); } else if (gameStatus->getMenuItem() == RESUME && gameStatus->getIsGameToResume()) { gameStatus->setGameState(game_state::MATCH); } else if (gameStatus->getMenuItem() == SIMULATION) { resetGameStatus(); gameStatus->setIsGameToResume(false); gameStatus->setGameState(game_state::SIMULATE); } else if (gameStatus->getMenuItem() == EXIT) { gameWindow->close(); } break; default: break; } } void GameController::gameMatch(sf::RenderWindow *gameWindow, View *view) { if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Space)) gameStatus->startBall(BALL_PLAYERS_SPEED); gameStatus->movePaddles(); gameStatus->lookForCollisions(true); gameStatus->actualizeStatus(); view->prepareView(*gameStatus); view->displayView(gameWindow); if (gameStatus->score()) { if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Space)) gameStatus->startBall(BALL_PLAYERS_SPEED); } if (gameStatus->checkIfAnyPlayerWon()) { gameStatus->setGameState(game_state::GAME_OVER); } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) { gameStatus->setGameState(game_state::MENU); } } void GameController::gameMatchSimulation(sf::RenderWindow *gameWindow, View *view, bool isSimulation) { gameStatus->startBall(BALL_COMPUTER_SPEED); gameStatus->simulate(); gameStatus->lookForCollisions(false); gameStatus->actualizeStatus(); if (gameStatus->score()) gameStatus->startBall(BALL_COMPUTER_SPEED); view->prepareView(*gameStatus); view->displayView(gameWindow); if (gameStatus->checkIfAnyPlayerWon()) { gameStatus->setGameState(game_state::GAME_OVER); } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) { gameStatus->setGameState(game_state::MENU); } } void GameController::resetGameStatus() { pmem::obj::transaction::exec_tx( gamePoolG->getGamePool()->getPoolToTransaction(), [&] { pmem::obj::delete_persistent( gameStatus); gameStatus = pmem::obj::make_persistent(); }); } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameController.hpp000066400000000000000000000050041331545616200242560ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GAMECONTROLLER_H_ #define GAMECONTROLLER_H_ #include "GameConstants.hpp" #include "GameOverView.hpp" #include "GameView.hpp" #include "MenuView.hpp" #include "PongGameStatus.hpp" #include #include #include #include #include class GameController { public: GameController(); ~GameController(); void gameLoop(bool isSimulation = false); private: pmem::obj::persistent_ptr gameStatus; void gameOver(sf::RenderWindow *gameWindow, View *view); void menu(sf::RenderWindow *gameWindow, View *view); void handleEventKeypress(sf::Event &event, sf::RenderWindow *gameWindow); void gameMatch(sf::RenderWindow *gameWindow, View *view); void gameMatchSimulation(sf::RenderWindow *gameWindow, View *view, bool isOnlySimulation); void resetGameStatus(); }; #endif /* GAMECONTROLLER_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameOverView.cpp000066400000000000000000000056161331545616200237050ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "GameOverView.hpp" GameOverView::GameOverView(sf::Font &font) { gameOver.setString("GAME OVER"); entContinue.setString("press ENTER to continue"); playerWinner.setString(""); gameOver.setFont(font); playerWinner.setFont(font); entContinue.setFont(font); gameOver.setCharacterSize(GAMEOVER_FONTSIZE); playerWinner.setCharacterSize(MENUVIEW_ITEMS_FONTSIZE); entContinue.setCharacterSize(MENUVIEW_ITEMS_FONTSIZE); gameOver.setPosition( WINDOW_WIDTH / 2 - gameOver.getGlobalBounds().width / 2, 0); playerWinner.setPosition( WINDOW_WIDTH / 2 - playerWinner.getGlobalBounds().width / 2, GAMOVERVIEW_OFFSET * 2); entContinue.setPosition(WINDOW_WIDTH / 2 - entContinue.getGlobalBounds().width / 2, WINDOW_HEIGHT - GAMOVERVIEW_OFFSET); gameOver.setFillColor(sf::Color::Red); playerWinner.setFillColor(sf::Color::Green); entContinue.setFillColor(sf::Color::White); } GameOverView::~GameOverView() { } void GameOverView::prepareView(PongGameStatus &gameStatus) { if (gameStatus.getPlayer1()->getPoints() == POINTS_TO_WIN) playerWinner.setString("LEFT PLAYER WON!"); else playerWinner.setString("RIGHT PLAYER WON!"); } void GameOverView::displayView(sf::RenderWindow *gameWindow) { gameWindow->clear(); gameWindow->draw(gameOver); gameWindow->draw(playerWinner); gameWindow->draw(entContinue); gameWindow->display(); } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameOverView.hpp000066400000000000000000000040251331545616200237030ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GAMEOVERVIEW_H_ #define GAMEOVERVIEW_H_ #include "GameConstants.hpp" #include "PongGameStatus.hpp" #include "View.hpp" #include class GameOverView : public View { public: GameOverView(sf::Font &font); ~GameOverView(); virtual void prepareView(PongGameStatus &gameStatus); virtual void displayView(sf::RenderWindow *gameWindow); private: sf::Text gameOver; sf::Text playerWinner; sf::Text entContinue; }; #endif /* GAMEOVERVIEW_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameView.cpp000066400000000000000000000116311331545616200230430ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "GameView.hpp" GameView::GameView(sf::Font &font) { sf::Color elementsColor(224, 224, 224); scoreP1.setFont(font); scoreP2.setFont(font); scoreP1.setCharacterSize(GAMEVIEW_SCORE_FONTSIZE); scoreP2.setCharacterSize(GAMEVIEW_SCORE_FONTSIZE); scoreP1.setPosition(WINDOW_WIDTH / 2 - SCORE_VIEW_OFFSET, SCORE_VIEW_OFFSET); scoreP2.setPosition(WINDOW_WIDTH / 2 + SCORE_VIEW_OFFSET - scoreP2.getGlobalBounds().width, SCORE_VIEW_OFFSET); scoreP1.setFillColor(sf::Color::Green); scoreP2.setFillColor(sf::Color::Green); upperLine.setPosition(VERTICAL_LINE_OFFSET, scoreP1.getPosition().y + HORIZONAL_LINE_OFFSET); upperLine.setSize(sf::Vector2f(WINDOW_WIDTH - 2 * VERTICAL_LINE_OFFSET, LINE_THICKNESS)); upperLine.setFillColor(elementsColor); downLine.setPosition(VERTICAL_LINE_OFFSET, WINDOW_HEIGHT - HORIZONAL_LINE_OFFSET); downLine.setSize(sf::Vector2f(WINDOW_WIDTH - 2 * VERTICAL_LINE_OFFSET + LINE_THICKNESS, LINE_THICKNESS)); downLine.setFillColor(elementsColor); leftLine.setPosition(VERTICAL_LINE_OFFSET, scoreP1.getPosition().y + HORIZONAL_LINE_OFFSET); leftLine.setSize(sf::Vector2f( LINE_THICKNESS, WINDOW_HEIGHT - (scoreP1.getPosition().y + 2 * HORIZONAL_LINE_OFFSET))); leftLine.setFillColor(elementsColor); rightLine.setPosition(WINDOW_WIDTH - VERTICAL_LINE_OFFSET, scoreP1.getPosition().y + HORIZONAL_LINE_OFFSET); rightLine.setSize(sf::Vector2f( LINE_THICKNESS, WINDOW_HEIGHT - (scoreP1.getPosition().y + 2 * HORIZONAL_LINE_OFFSET))); rightLine.setFillColor(elementsColor); court.setPosition(VERTICAL_LINE_OFFSET + LINE_THICKNESS, scoreP1.getPosition().y + HORIZONAL_LINE_OFFSET); court.setSize(sf::Vector2f( WINDOW_WIDTH - 2 * VERTICAL_LINE_OFFSET, WINDOW_HEIGHT - (scoreP1.getPosition().y + 2 * HORIZONAL_LINE_OFFSET))); court.setFillColor(sf::Color(60, 132, 48)); ballShape.setRadius(BALL_SIZE); ballShape.setPosition(sf::Vector2f(0, 0)); ballShape.setFillColor(elementsColor); rightPaddleShape.setSize(sf::Vector2f(PADDLE_WIDTH, PADDLE_HEIGHT)); leftPaddleShape.setSize(sf::Vector2f(PADDLE_WIDTH, PADDLE_HEIGHT)); leftPaddleShape.setPosition(sf::Vector2f(0, 0)); rightPaddleShape.setPosition(sf::Vector2f(0, 0)); leftPaddleShape.setFillColor(sf::Color::Red); rightPaddleShape.setFillColor(sf::Color::Red); } GameView::~GameView() { } void GameView::prepareView(PongGameStatus &gameStatus) { scoreP1.setString(std::to_string(gameStatus.getPlayer1()->getPoints())); scoreP2.setString(std::to_string(gameStatus.getPlayer2()->getPoints())); ballShape.setPosition( sf::Vector2f((float)gameStatus.getBall()->getX(), (float)gameStatus.getBall()->getY())); leftPaddleShape.setPosition( sf::Vector2f((float)gameStatus.getPlayer1()->getX(), (float)gameStatus.getPlayer1()->getY())); rightPaddleShape.setPosition( sf::Vector2f((float)gameStatus.getPlayer2()->getX(), (float)gameStatus.getPlayer2()->getY())); } void GameView::displayView(sf::RenderWindow *gameWindow) { gameWindow->clear(); gameWindow->draw(court); gameWindow->draw(upperLine); gameWindow->draw(leftLine); gameWindow->draw(downLine); gameWindow->draw(rightLine); gameWindow->draw(scoreP1); gameWindow->draw(scoreP2); gameWindow->draw(ballShape); gameWindow->draw(leftPaddleShape); gameWindow->draw(rightPaddleShape); gameWindow->display(); } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/GameView.hpp000066400000000000000000000043601331545616200230510ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GAMEVIEW_H_ #define GAMEVIEW_H_ #include "GameConstants.hpp" #include "PongGameStatus.hpp" #include "View.hpp" #include #include class GameView : public View { public: GameView(sf::Font &font); ~GameView(); virtual void prepareView(PongGameStatus &gameStatus); virtual void displayView(sf::RenderWindow *gameWindow); private: sf::Text scoreP1; sf::Text scoreP2; sf::RectangleShape upperLine; sf::RectangleShape downLine; sf::RectangleShape leftLine; sf::RectangleShape rightLine; sf::RectangleShape court; sf::CircleShape ballShape; sf::RectangleShape leftPaddleShape; sf::RectangleShape rightPaddleShape; }; #endif /* GAMEVIEW_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/MainGame.cpp000066400000000000000000000054771331545616200230300ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Pool.hpp" #include #include #include #include #include #include int main(int argc, char *argv[]) { int exitCode = EXIT_FAILURE; std::string mode = ""; if (argc == 3) { mode = argv[2]; } if (argc < 2 || argc > 3 || (argc == 3 && mode != "-s")) { std::cout << "Usage: ./pmpong " "[options]" << std::endl << "Options: " << std::endl << "-s, simulates game between 2 AI players" << std::endl; return exitCode; } std::string fileName = argv[1]; try { Pool *pool = Pool::getGamePoolFromFile(fileName); pmem::obj::persistent_ptr gameController = pool->getGameController(); if (mode == "-s") gameController->gameLoop(true); else gameController->gameLoop(); delete pool; exitCode = EXIT_SUCCESS; } catch (pmem::transaction_error &err) { std::cerr << err.what() << std::endl; } catch (pmem::transaction_scope_error &tse) { std::cerr << tse.what() << std::endl; } catch (pmem::pool_error &pe) { std::cerr << pe.what() << std::endl; } catch (std::logic_error &le) { std::cerr << le.what() << std::endl; } catch (std::exception &exc) { std::cerr << exc.what() << std::endl; } return exitCode; } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Makefile000066400000000000000000000045321331545616200222750ustar00rootroot00000000000000# # Copyright 2017-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. TOP := $(dir $(lastword $(MAKEFILE_LIST)))../../../../ include $(TOP)/src/common.inc SFML := $(call check_package, sfml-all --atleast-version 2.4) ifeq ($(SFML),y) ifeq ($(shell uname -s),FreeBSD) FONTDIR=/usr/local/share/fonts else FONTDIR=/usr/share/fonts endif PROGS = pmpong else $(info NOTE: Skipping pmpong because sfml is missing \ -- see src/examples/libpmemobj/pmpong/README for details.) endif LIBS = -lpmemobj -lpmem ifeq ($(SFML),y) LIBS += $(shell $(PKG_CONFIG) --libs sfml-all) endif COMPILE_LANG = cpp include ../../Makefile.inc INCS += -I../ pmpong: MainGame.o Paddle.o Ball.o PongGameStatus.o GameController.o Pool.o GameView.o MenuView.o GameOverView.o rm-fontconf: rm -f fontConf clobber: rm-fontconf clean: rm-fontconf fontConf: find $(FONTDIR) -name *.ttf | head -n 1 > fontConf all: fontConf pmdk-1.4.1/src/examples/libpmemobj++/pmpong/MenuView.cpp000066400000000000000000000052261331545616200231010ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "MenuView.hpp" MenuView::MenuView(sf::Font &font) { menuItems[NEW_GAME].setString("NEW GAME"); menuItems[RESUME].setString("RESUME"); menuItems[SIMULATION].setString("SIMULATION"); menuItems[EXIT].setString("EXIT"); for (int i = 0; i < MENU_ITEMS; i++) { menuItems[i].setFont(font); menuItems[i].setCharacterSize(MENUVIEW_ITEMS_FONTSIZE); menuItems[i].setPosition( WINDOW_WIDTH / 2 - (float)menuItems[i].getGlobalBounds().width / 2, (float)(i + 1) * MENUITEM_OFFSET - MENUVIEW_ITEMS_FONTSIZE); } } MenuView::~MenuView() { } void MenuView::prepareView(PongGameStatus &gameStatus) { for (int i = 0; i < MENU_ITEMS; i++) { if (i == gameStatus.getMenuItem()) { menuItems[i].setFillColor(sf::Color::Green); } else if (i == RESUME && !gameStatus.getIsGameToResume()) { menuItems[RESUME].setFillColor(sf::Color::White); } else { menuItems[i].setFillColor(sf::Color::Red); } } } void MenuView::displayView(sf::RenderWindow *gameWindow) { gameWindow->clear(); for (int i = 0; i < MENU_ITEMS; i++) { gameWindow->draw(menuItems[i]); } gameWindow->display(); } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/MenuView.hpp000066400000000000000000000040241331545616200231010ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MENUVIEW_H_ #define MENUVIEW_H_ #include "GameConstants.hpp" #include "PongGameStatus.hpp" #include "View.hpp" #include enum menu_items { NEW_GAME, RESUME, SIMULATION, EXIT }; class MenuView : public View { public: MenuView(sf::Font &font); ~MenuView(); virtual void prepareView(PongGameStatus &gameStatus); virtual void displayView(sf::RenderWindow *gameWindow); private: sf::Text menuItems[MENU_ITEMS]; }; #endif /* MENUVIEW_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Paddle.cpp000066400000000000000000000076121331545616200225340ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Paddle.hpp" #include "Pool.hpp" Pool *gamePoolP; Paddle::Paddle(int x, int y) { this->x = x; this->y = y; this->points = 0; init(); } Paddle::~Paddle() { } void Paddle::moveUp(int velocity) { if (!(this->y - velocity < SCORE_VIEW_OFFSET + HORIZONAL_LINE_OFFSET + LINE_THICKNESS)) { setY(this->y - velocity); } else if (this->y - velocity < SCORE_VIEW_OFFSET + HORIZONAL_LINE_OFFSET + LINE_THICKNESS) { setY(SCORE_VIEW_OFFSET + HORIZONAL_LINE_OFFSET + LINE_THICKNESS); } } void Paddle::moveDown(int velocity) { if (!(this->y + PADDLE_HEIGHT + velocity > WINDOW_HEIGHT - HORIZONAL_LINE_OFFSET - LINE_THICKNESS)) { setY(this->y + velocity); } else if (this->y + PADDLE_HEIGHT + velocity > WINDOW_HEIGHT - HORIZONAL_LINE_OFFSET - LINE_THICKNESS) { setY(WINDOW_HEIGHT - HORIZONAL_LINE_OFFSET - PADDLE_HEIGHT); } } void Paddle::addPoint() { setPoints(points + 1); } void Paddle::init() { setY(WINDOW_HEIGHT / 2 - (int)getPaddleShape().getSize().y / 2); } void Paddle::adjustPaddleYtoBall(Ball &ball) { if (this->y > ball.getY()) moveUp(PADDLE_VELOCITY_COMPUTER); if (this->y + getPaddleShape().getGlobalBounds().height - ball.getBallShape().getRadius() * 4 < ball.getY()) moveDown(PADDLE_VELOCITY_COMPUTER); } void Paddle::collisionWithBall(Ball &ball, bool increaseBallSpeed) { if (ball.getBallShape().getGlobalBounds().intersects( getPaddleShape().getGlobalBounds())) { ball.setVelocityX(ball.getVelocity()->x * (-1)); if (increaseBallSpeed) ball.increaseVelocity(); } } int Paddle::getX() { return this->x; } int Paddle::getY() { return this->y; } int Paddle::getPoints() { return this->points; } sf::RectangleShape Paddle::getPaddleShape() { sf::RectangleShape shapeToRet; shapeToRet.setSize(sf::Vector2f(PADDLE_WIDTH, PADDLE_HEIGHT)); shapeToRet.setPosition(sf::Vector2f((float)this->x, (float)this->y)); return shapeToRet; } void Paddle::setPoints(int pointsArg) { pmem::obj::transaction::exec_tx( gamePoolP->getGamePool()->getPoolToTransaction(), [&] { points = pointsArg; }); } void Paddle::setY(int yArg) { pmem::obj::transaction::exec_tx( gamePoolP->getGamePool()->getPoolToTransaction(), [&] { y = yArg; }); } void Paddle::setX(int xArg) { pmem::obj::transaction::exec_tx( gamePoolP->getGamePool()->getPoolToTransaction(), [&] { x = xArg; }); } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Paddle.hpp000066400000000000000000000044541331545616200225420ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef PADDLE_H_ #define PADDLE_H_ #include "Ball.hpp" #include "GameConstants.hpp" #include #include #include #include class Paddle { public: Paddle(); Paddle(int x, int y); ~Paddle(); void moveUp(int velocity); void moveDown(int velocity); void addPoint(); void init(); void adjustPaddleYtoBall(Ball &ball); void collisionWithBall(Ball &ball, bool increaseBallSpeed); int getX(); int getY(); int getPoints(); sf::RectangleShape getPaddleShape(); private: pmem::obj::p y; pmem::obj::p x; pmem::obj::p points; void setPoints(int pointsArg); void setY(int yArg); void setX(int xArg); }; #endif /* PADDLE_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/PongGameStatus.cpp000066400000000000000000000126741331545616200242500ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "PongGameStatus.hpp" #include "Pool.hpp" Pool *gamePool; PongGameStatus::PongGameStatus() { player1 = pmem::obj::make_persistent( VERTICAL_LINE_OFFSET + LINE_THICKNESS, WINDOW_HEIGHT / 2); player2 = pmem::obj::make_persistent( WINDOW_WIDTH - VERTICAL_LINE_OFFSET - PADDLE_WIDTH, WINDOW_HEIGHT / 2); ball = pmem::obj::make_persistent(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); menuItem = 0; isGameToResume = false; actualGameState = game_state::MENU; } PongGameStatus::~PongGameStatus() { pmem::obj::transaction::exec_tx( gamePool->getGamePool()->getPoolToTransaction(), [&] { pmem::obj::delete_persistent(player1); pmem::obj::delete_persistent(player2); pmem::obj::delete_persistent(ball); }); } void PongGameStatus::startBall(float ballSpeed) { if (ball->getVelocity()->x == 0 && ball->getVelocity()->y == 0) { float x = randomizeFloatValue(1.5, 2.0); ball->setVelocityX(randomizeDirection() ? ballSpeed : -ballSpeed); ball->setVelocityY(randomizeDirection() ? x : -1 * x); } } void PongGameStatus::reset() { ball->init(); player1->init(); player2->init(); } void PongGameStatus::movePaddles() { if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W)) { player1->moveUp(PADDLE_VELOCITY_PLAYER); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S)) { player1->moveDown(PADDLE_VELOCITY_PLAYER); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Up)) { player2->moveUp(PADDLE_VELOCITY_PLAYER); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Down)) { player2->moveDown(PADDLE_VELOCITY_PLAYER); } } void PongGameStatus::lookForCollisions(bool increaseBallVelocity) { player1->collisionWithBall(*ball, increaseBallVelocity); player2->collisionWithBall(*ball, increaseBallVelocity); ball->collisionWithWindow(); } void PongGameStatus::actualizeStatus() { ball->move(); } void PongGameStatus::simulate() { if (ball->getVelocity()->x > 0) player2->adjustPaddleYtoBall(*ball); if (ball->getVelocity()->x < 0) player1->adjustPaddleYtoBall(*ball); } void PongGameStatus::setMenuItem(int numb) { pmem::obj::transaction::exec_tx( gamePool->getGamePool()->getPoolToTransaction(), [&] { this->menuItem = numb; }); } void PongGameStatus::setIsGameToResume(bool isGameToRes) { pmem::obj::transaction::exec_tx( gamePool->getGamePool()->getPoolToTransaction(), [&] { isGameToResume = isGameToRes; }); } void PongGameStatus::setGameState(game_state state) { pmem::obj::transaction::exec_tx( gamePool->getGamePool()->getPoolToTransaction(), [&] { this->actualGameState = state; }); } int PongGameStatus::getMenuItem() { return this->menuItem; } float PongGameStatus::randomizeFloatValue(float min, float max) { return (min + 1) + (((float)rand()) / (float)RAND_MAX) * (max - (min + 1)); } bool PongGameStatus::score() { if (ball->getBallShape().getPosition().x > WINDOW_WIDTH - VERTICAL_LINE_OFFSET + LINE_THICKNESS - ball->getBallShape().getRadius() * 2) { player1->addPoint(); reset(); return true; } if (ball->getBallShape().getPosition().x < VERTICAL_LINE_OFFSET - LINE_THICKNESS) { player2->addPoint(); reset(); return true; } return false; } bool PongGameStatus::checkIfAnyPlayerWon() { if (getPlayer1()->getPoints() == POINTS_TO_WIN || getPlayer2()->getPoints() == POINTS_TO_WIN) return true; return false; } bool PongGameStatus::randomizeDirection() { static const int shift = static_cast(std::log2(RAND_MAX)); return (rand() >> shift) & 1; } bool PongGameStatus::getIsGameToResume() { return this->isGameToResume; } pmem::obj::persistent_ptr PongGameStatus::getPlayer1() { return this->player1; } pmem::obj::persistent_ptr PongGameStatus::getPlayer2() { return this->player2; } pmem::obj::persistent_ptr PongGameStatus::getBall() { return this->ball; } game_state PongGameStatus::getGameState() { return this->actualGameState; } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/PongGameStatus.hpp000066400000000000000000000055131331545616200242470ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef PONGGAMESTATUS_H_ #define PONGGAMESTATUS_H_ #include "Ball.hpp" #include "GameConstants.hpp" #include "Paddle.hpp" #include #include #include #include enum game_state { MATCH, MENU, GAME_OVER, SIMULATE }; class PongGameStatus { public: PongGameStatus(); ~PongGameStatus(); void startBall(float ballSpeed); void reset(); void movePaddles(); void lookForCollisions(bool increaseBallVelocity); void actualizeStatus(); void simulate(); void setMenuItem(int numb); void setIsGameToResume(bool isGameToRes); void setGameState(game_state state); int getMenuItem(); float randomizeFloatValue(float min, float max); bool score(); bool checkIfAnyPlayerWon(); bool randomizeDirection(); bool getIsGameToResume(); pmem::obj::persistent_ptr getPlayer1(); pmem::obj::persistent_ptr getPlayer2(); pmem::obj::persistent_ptr getBall(); game_state getGameState(); private: pmem::obj::persistent_ptr player1; pmem::obj::persistent_ptr player2; pmem::obj::persistent_ptr ball; pmem::obj::p menuItem; pmem::obj::p isGameToResume; pmem::obj::p actualGameState; }; #endif /* PONGGAMESTATUS_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Pool.cpp000066400000000000000000000051471331545616200222550ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Pool.hpp" Pool *Pool::pongPool = nullptr; Pool::Pool(const std::string &fileName) { if (pmem::obj::pool::check(fileName, LAYOUT_NAME) == 1) { pool = pmem::obj::pool::open(fileName, LAYOUT_NAME); } else { pool = pmem::obj::pool::create( fileName, LAYOUT_NAME, PMEMOBJ_MIN_POOL * 6); } } Pool::~Pool() { pool.close(); } Pool * Pool::getGamePoolFromFile(const std::string &fileName) { if (pongPool == nullptr) pongPool = new Pool(fileName); return pongPool; } Pool * Pool::getGamePool() { if (pongPool == nullptr) { return getGamePoolFromFile(DEFAULT_POOLFILE_NAME); } return pongPool; } pmem::obj::persistent_ptr Pool::getGameController() { pmem::obj::persistent_ptr root = pool.get_root(); if (root != nullptr) { if (root->gam == nullptr) pmem::obj::transaction::exec_tx(pool, [&] { root->gam = pmem::obj::make_persistent< GameController>(); }); } return root->gam; } pmem::obj::pool & Pool::getPoolToTransaction() { return pool; } pmdk-1.4.1/src/examples/libpmemobj++/pmpong/Pool.hpp000066400000000000000000000043621331545616200222600ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef POOL_H_ #define POOL_H_ #include "GameController.hpp" #include #include #include #include struct GameStruct { public: pmem::obj::persistent_ptr gam; }; class Pool { public: ~Pool(); static Pool *getGamePoolFromFile(const std::string &fileName); static Pool *getGamePool(); pmem::obj::persistent_ptr getGameController(); pmem::obj::pool &getPoolToTransaction(); private: Pool(const std::string &name); static Pool *pongPool; pmem::obj::pool pool; Pool(const Pool &); Pool &operator=(const Pool &); }; #endif /* POOL_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/README000066400000000000000000000020131331545616200215050ustar00rootroot00000000000000 Persistent Memory Development Kit This is examples/libpmemobj++/pmpong/README. This directory contains an example application implemented using libpmemobj, it's a game in which all the objects are stored on persistent memory. This means that the game process can be safely killed and then resumed. To launch the game: ./pmpong [mode] Mode option might be skipped if you want to run game with GUI or use -s to run game simulation. The file with the game session will either be created if it doesn't exist or opened if it contains a valid pool. Controls: move left paddle - up and down arrow keys move right paddle - 'w' and 's' pause - esc start ball - space This game demonstrates the usage of the very basics of the libpmemobj C++ bindings. It demonstrates pool management, persistent pointers and transactions. ** DEPENDENCIES: ** In order to build the game you need to have SFML 2.4+ installed. rpm-based systems : sudo dnf install SFML-devel dpkg-based systems: sudo apt-get install libsfml-dev pmdk-1.4.1/src/examples/libpmemobj++/pmpong/View.hpp000066400000000000000000000035601331545616200222600ustar00rootroot00000000000000/* * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VIEW_H_ #define VIEW_H_ #include "GameConstants.hpp" #include "PongGameStatus.hpp" #include class View { public: virtual ~View(){}; virtual void prepareView(PongGameStatus &gameStatus) = 0; virtual void displayView(sf::RenderWindow *gameWindow) = 0; }; #endif /* VIEW_H_ */ pmdk-1.4.1/src/examples/libpmemobj++/pmpong/buildScript.ps1000066400000000000000000000044371331545616200235520ustar00rootroot00000000000000# Copyright 2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # buildScript.ps1 -- script for downloading and copying SFML files # $url = "https://www.sfml-dev.org/files/SFML-2.4.2-windows-vc14-64-bit.zip" $Filename = [System.IO.Path]::GetFileName($url) $path = "$env:TEMP\$Filename" $webClient = new-object System.Net.WebClient $webClient.DownloadFile($url,$path) $SFMLFileExists = Test-Path $env:TEMP\SFML-2.4.2 if ($SFMLFileExists -eq $False) { $shell = New-Object -ComObject shell.application $zip = $shell.NameSpace($path) foreach ($item in $zip.items()) { $shell.Namespace($env:TEMP).CopyHere($item) } } Copy-Item $env:TEMP\SFML-2.4.2\bin\* -Destination $env:TargetDir Copy-Item $env:TEMP\SFML-2.4.2\include -Destination $env:TargetDir -recurse Copy-Item $env:TEMP\SFML-2.4.2\lib -Destination $env:TargetDir -recurse pmdk-1.4.1/src/examples/libpmemobj++/pmpong/pmpong.vcxproj000066400000000000000000000136611331545616200235550ustar00rootroot00000000000000 Debug x64 Release x64 {C6E9D8C2-D5C1-441B-95ED-378E10DC5723} Win32Proj pmemobj 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true ..\..\..\LongPath.manifest true $(VC_IncludePath);$(WindowsSDK_IncludePath);$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ false $(VC_IncludePath);$(WindowsSDK_IncludePath);$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) $(ProjectDir)\include;%(AdditionalIncludeDirectories) Console true $(ProjectDir)\lib;%(AdditionalLibraryDirectories) sfml-graphics-d.lib;sfml-window-d.lib;sfml-system-d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) PowerShell -ExecutionPolicy RemoteSigned -file $(ProjectDir)buildScript.ps1 NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(ProjectDir)\include;%(AdditionalIncludeDirectories) Console true $(ProjectDir)\lib;%(AdditionalLibraryDirectories) sfml-graphics.lib;sfml-window.lib;sfml-system.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) PowerShell -ExecutionPolicy RemoteSigned -file $(ProjectDir)buildScript.ps1 pmdk-1.4.1/src/examples/libpmemobj++/pmpong/pmpong.vcxproj.filters000066400000000000000000000046251331545616200252240ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files pmdk-1.4.1/src/examples/libpmemobj++/queue/000077500000000000000000000000001331545616200204555ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj++/queue/.gitignore000066400000000000000000000000061331545616200224410ustar00rootroot00000000000000queue pmdk-1.4.1/src/examples/libpmemobj++/queue/Makefile000066400000000000000000000032201331545616200221120ustar00rootroot00000000000000# # Copyright 2015-2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # PROGS = queue LIBS = -lpmemobj -lpmem -pthread COMPILE_LANG = cpp include ../../Makefile.inc queue: queue.o pmdk-1.4.1/src/examples/libpmemobj++/queue/queue.cpp000066400000000000000000000115471331545616200223150ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue.cpp -- queue example implemented using pmemobj cpp bindings * * Please see pmem.io blog posts for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define LAYOUT "queue" namespace { /* available queue operations */ enum queue_op { UNKNOWN_QUEUE_OP, QUEUE_PUSH, QUEUE_POP, QUEUE_SHOW, MAX_QUEUE_OP, }; /* queue operations strings */ const char *ops_str[MAX_QUEUE_OP] = {"", "push", "pop", "show"}; /* * parse_queue_op -- parses the operation string and returns matching queue_op */ queue_op parse_queue_op(const char *str) { for (int i = 0; i < MAX_QUEUE_OP; ++i) if (strcmp(str, ops_str[i]) == 0) return (queue_op)i; return UNKNOWN_QUEUE_OP; } } using pmem::obj::p; using pmem::obj::persistent_ptr; using pmem::obj::pool; using pmem::obj::pool_base; using pmem::obj::make_persistent; using pmem::obj::delete_persistent; using pmem::obj::transaction; namespace examples { /* * Persistent memory list-based queue * * A simple, not template based, implementation of queue using * libpmemobj C++ API. It demonstrates the basic features of persistent_ptr<> * and p<> classes. */ class pmem_queue { /* entry in the list */ struct pmem_entry { persistent_ptr next; p value; }; public: /* * Inserts a new element at the end of the queue. */ void push(pool_base &pop, uint64_t value) { transaction::exec_tx(pop, [&] { auto n = make_persistent(); n->value = value; n->next = nullptr; if (head == nullptr && tail == nullptr) { head = tail = n; } else { tail->next = n; tail = n; } }); } /* * Removes the first element in the queue. */ uint64_t pop(pool_base &pop) { uint64_t ret = 0; transaction::exec_tx(pop, [&] { if (head == nullptr) transaction::abort(EINVAL); ret = head->value; auto n = head->next; delete_persistent(head); head = n; if (head == nullptr) tail = nullptr; }); return ret; } /* * Prints the entire contents of the queue. */ void show(void) const { for (auto n = head; n != nullptr; n = n->next) std::cout << n->value << std::endl; } private: persistent_ptr head; persistent_ptr tail; }; } /* namespace examples */ int main(int argc, char *argv[]) { if (argc < 3) { std::cerr << "usage: " << argv[0] << " file-name [push [value]|pop|show]" << std::endl; return 1; } const char *path = argv[1]; queue_op op = parse_queue_op(argv[2]); pool pop; if (file_exists(path) != 0) { pop = pool::create( path, LAYOUT, PMEMOBJ_MIN_POOL, CREATE_MODE_RW); } else { pop = pool::open(path, LAYOUT); } auto q = pop.get_root(); switch (op) { case QUEUE_PUSH: q->push(pop, atoll(argv[3])); break; case QUEUE_POP: std::cout << q->pop(pop) << std::endl; break; case QUEUE_SHOW: q->show(); break; default: throw std::invalid_argument("invalid queue operation"); } pop.close(); return 0; } pmdk-1.4.1/src/examples/libpmemobj++/queue/queue.vcxproj000066400000000000000000000051551331545616200232240ustar00rootroot00000000000000 Debug x64 Release x64 {A6CC801B-CF30-4703-BC54-3E21F90B787D} pmemobj_cpp 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest pmdk-1.4.1/src/examples/libpmemobj++/queue/queue.vcxproj.filters000066400000000000000000000006441331545616200246710ustar00rootroot00000000000000 {cba2d0d1-54c5-4fc4-9770-886749ac95b8} Source Files pmdk-1.4.1/src/examples/libpmemobj/000077500000000000000000000000001331545616200172035ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj/.gitignore000066400000000000000000000000471331545616200211740ustar00rootroot00000000000000*~ pi manpage btree rtree lists setjmp pmdk-1.4.1/src/examples/libpmemobj/Makefile000066400000000000000000000040041331545616200206410ustar00rootroot00000000000000# # Copyright 2014-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemobj/Makefile -- build the libpmemobj examples # PROGS = manpage btree pi lists setjmp DIRS = pminvaders pmemlog pmemblk string_store string_store_tx\ string_store_tx_type hashmap tree_map pmemobjfs map libart array\ linkedlist list_map slab_allocator LIBS = -lpmemobj -lpmem -pthread -lm -pthread include ../Makefile.inc map: hashmap tree_map pmemobjfs: map manpage: manpage.o btree: btree.o pi: pi.o lists: lists.o setjmp: CFLAGS += -O2 setjmp: setjmp.o pmdk-1.4.1/src/examples/libpmemobj/README000066400000000000000000000011701331545616200200620ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemobj/README. This directory contains examples for libpmemobj, the library providing a transactional object store for pmem. Some of these examples are explained in more detail here: http://pmem.io/pmdk/libpmemobj manpage.c and setjmp.c are the examples used in the libpmemobj man page. To build these examples: make These examples can be built against an installed system using: make LIBDIR=/usr/lib INCDIR=/usr/include If you're looking for documentation to get you started using PMDK, start here: http://pmem.io/pmdk and follow the links to examples and man pages. pmdk-1.4.1/src/examples/libpmemobj/array/000077500000000000000000000000001331545616200203215ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj/array/.gitignore000066400000000000000000000000061331545616200223050ustar00rootroot00000000000000array pmdk-1.4.1/src/examples/libpmemobj/array/Makefile000066400000000000000000000032751331545616200217700ustar00rootroot00000000000000# # Copyright 2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # examples/libpmemobj/array/Makefile -- build the array example # PROGS = array LIBS = -lpmemobj -lpmem -pthread include ../../Makefile.inc array: array.o pmdk-1.4.1/src/examples/libpmemobj/array/README000066400000000000000000000035451331545616200212100ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemobj/array/README. This directory contains an example application implemented using libpmemobj. The array example allows to perform basic operations like allocation, reallocation and de-allocation on persistent array. User can choose size of new or reallocated array. There are also 3 types of elements which are supported: int, PMEMoid and TOID with structure containing int variable. Persistent pointer can be treated as a pointer to the first element of array. TOID with user's defined structure can be allocated by using POBJ_ALLOC or POBJ_ZALLOC macros (similarly when using PMEMoid there are pmemobj_alloc() and pmemobj_zalloc() functions) with proper number elements multiplied by user-defined structure's size. Access to array's elements can be executed by using pmemobj_direct() function or just using proper macro. For example D_RW(test1)[0] points to first element of test1 array. To allocate new array using application run the following command: $ array alloc Where is file where pool will be created or opened, is user's defined unique name, is number of elements of persistent array and is one of listed: int, PMEMoid, TOID. To reallocate existing array run the following command: $ array realloc To free existing array run the following command: $ array free To print array's elements run the following command: $ array print Example of usage: $ array /mnt/pmem/testfile alloc test1 10 TOID $ array /mnt/pmem/testfile alloc test2 100 int $ array /mnt/pmem/testfile realloc test1 50 $ array /mnt/pmem/testfile realloc test2 5 $ array /mnt/pmem/testfile print test1 $ array /mnt/pmem/testfile free test1 $ array /mnt/pmem/testfile free test2 pmdk-1.4.1/src/examples/libpmemobj/array/array.c000066400000000000000000000316461331545616200216150ustar00rootroot00000000000000/* * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * array.c -- example of arrays usage */ #include #include #include #include #include #include #include #define TOID_ARRAY(x) TOID(x) #define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) #define MAX_BUFFLEN 30 #define MAX_TYPE_NUM 8 POBJ_LAYOUT_BEGIN(array); POBJ_LAYOUT_TOID(array, struct array_elm); POBJ_LAYOUT_TOID(array, int); POBJ_LAYOUT_TOID(array, PMEMoid); POBJ_LAYOUT_TOID(array, TOID(struct array_elm)); POBJ_LAYOUT_TOID(array, struct array_info); POBJ_LAYOUT_END(array); static PMEMobjpool *pop; enum array_types { UNKNOWN_ARRAY_TYPE, INT_ARRAY_TYPE, PMEMOID_ARRAY_TYPE, TOID_ARRAY_TYPE, MAX_ARRAY_TYPE }; struct array_elm { int id; }; struct array_info { char name[MAX_BUFFLEN]; size_t size; enum array_types type; PMEMoid array; }; /* * print_usage -- print general usage */ static void print_usage(void) { printf("usage: ./array " "" " [ []]\n"); } /* * get type -- parse argument given as type of array */ static enum array_types get_type(const char *type_name) { const char *names[MAX_ARRAY_TYPE] = {"", "int", "PMEMoid", "TOID"}; enum array_types type; for (type = (enum array_types)(MAX_ARRAY_TYPE - 1); type > UNKNOWN_ARRAY_TYPE; type = (enum array_types)(type - 1)) { if (strcmp(names[type], type_name) == 0) break; } if (type == UNKNOWN_ARRAY_TYPE) fprintf(stderr, "unknown type: %s\n", type_name); return type; } /* * find_aray -- return info about array with proper name */ static TOID(struct array_info) find_array(const char *name) { TOID(struct array_info) info; POBJ_FOREACH_TYPE(pop, info) { if (strncmp(D_RO(info)->name, name, MAX_BUFFLEN) == 0) return info; } return TOID_NULL(struct array_info); } /* * elm_constructor -- constructor of array_elm type object */ static int elm_constructor(PMEMobjpool *pop, void *ptr, void *arg) { struct array_elm *obj = (struct array_elm *)ptr; int *id = (int *)arg; obj->id = *id; pmemobj_persist(pop, obj, sizeof(*obj)); return 0; } /* * print_int -- print array of int type */ static void print_int(struct array_info *info) { TOID(int) array; TOID_ASSIGN(array, info->array); for (size_t i = 0; i < info->size; i++) printf("%d ", D_RO(array)[i]); } /* * print_pmemoid -- print array of PMEMoid type */ static void print_pmemoid(struct array_info *info) { TOID(PMEMoid) array; TOID(struct array_elm) elm; TOID_ASSIGN(array, info->array); for (size_t i = 0; i < info->size; i++) { TOID_ASSIGN(elm, D_RW(array)[i]); printf("%d ", D_RO(elm)->id); } } /* * print_toid -- print array of TOID(struct array_elm) type */ static void print_toid(struct array_info *info) { TOID_ARRAY(TOID(struct array_elm)) array; TOID_ASSIGN(array, info->array); for (size_t i = 0; i < info->size; i++) printf("%d ", D_RO(D_RO(array)[i])->id); } typedef void (*fn_print)(struct array_info *info); static fn_print print_array[] = {NULL, print_int, print_pmemoid, print_toid}; /* * free_int -- de-allocate array of int type */ static void free_int(struct array_info *info) { TOID(int) array; TOID_ASSIGN(array, info->array); /* * When there is persistent array of simple type allocated, * there is enough to de-allocate persistent pointer */ POBJ_FREE(&array); } /* * free_pmemoid -- de-allocate array of PMEMoid type */ static void free_pmemoid(struct array_info *info) { TOID(PMEMoid) array; TOID_ASSIGN(array, info->array); /* * When there is persistent array of persistent pointer type allocated, * there is necessary to de-allocate each element, if they were * allocated earlier */ for (size_t i = 0; i < info->size; i++) pmemobj_free(&D_RW(array)[i]); POBJ_FREE(&array); } /* * free_toid -- de-allocate array of TOID(struct array_elm) type */ static void free_toid(struct array_info *info) { TOID_ARRAY(TOID(struct array_elm)) array; TOID_ASSIGN(array, info->array); /* * When there is persistent array of persistent pointer type allocated, * there is necessary to de-allocate each element, if they were * allocated earlier */ for (size_t i = 0; i < info->size; i++) POBJ_FREE(&D_RW(array)[i]); POBJ_FREE(&array); } typedef void (*fn_free)(struct array_info *info); static fn_free free_array[] = {NULL, free_int, free_pmemoid, free_toid}; /* * realloc_int -- reallocate array of int type */ static PMEMoid realloc_int(PMEMoid *info, size_t prev_size, size_t size) { TOID(int) array; TOID_ASSIGN(array, *info); POBJ_REALLOC(pop, &array, int, size * sizeof(int)); for (size_t i = prev_size; i < size; i++) D_RW(array)[i] = (int)i; return array.oid; } /* * realloc_pmemoid -- reallocate array of PMEMoid type */ static PMEMoid realloc_pmemoid(PMEMoid *info, size_t prev_size, size_t size) { TOID(PMEMoid) array; TOID_ASSIGN(array, *info); pmemobj_zrealloc(pop, &array.oid, sizeof(PMEMoid) * size, TOID_TYPE_NUM(PMEMoid)); for (size_t i = prev_size; i < size; i++) { if (pmemobj_alloc(pop, &D_RW(array)[i], sizeof(struct array_elm), TOID_TYPE_NUM(PMEMoid), elm_constructor, &i)) { fprintf(stderr, "pmemobj_alloc\n"); assert(0); } } return array.oid; } /* * realloc_toid -- reallocate array of TOID(struct array_elm) type */ static PMEMoid realloc_toid(PMEMoid *info, size_t prev_size, size_t size) { TOID_ARRAY(TOID(struct array_elm)) array; TOID_ASSIGN(array, *info); pmemobj_zrealloc(pop, &array.oid, sizeof(TOID(struct array_elm)) * size, TOID_TYPE_NUM_OF(array)); for (size_t i = prev_size; i < size; i++) { POBJ_NEW(pop, &D_RW(array)[i], struct array_elm, elm_constructor, &i); if (TOID_IS_NULL(D_RW(array)[i])) { fprintf(stderr, "POBJ_ALLOC\n"); assert(0); } } return array.oid; } typedef PMEMoid (*fn_realloc)(PMEMoid *info, size_t prev_size, size_t size); static fn_realloc realloc_array[] = {NULL, realloc_int, realloc_pmemoid, realloc_toid}; /* * alloc_int -- allocate array of int type */ static PMEMoid alloc_int(size_t size) { TOID(int) array; /* * To allocate persistent array of simple type is enough to allocate * pointer with size equal to number of elements multiplied by size of * user-defined structure. */ POBJ_ALLOC(pop, &array, int, sizeof(int) * size, NULL, NULL); if (TOID_IS_NULL(array)) { fprintf(stderr, "POBJ_ALLOC\n"); return OID_NULL; } for (size_t i = 0; i < size; i++) D_RW(array)[i] = (int)i; pmemobj_persist(pop, D_RW(array), size * sizeof(*D_RW(array))); return array.oid; } /* * alloc_pmemoid -- allocate array of PMEMoid type */ static PMEMoid alloc_pmemoid(size_t size) { TOID(PMEMoid) array; /* * To allocate persistent array of PMEMoid type is necessary to allocate * pointer with size equal to number of elements multiplied by size of * PMEMoid and to allocate each of elements separately. */ POBJ_ALLOC(pop, &array, PMEMoid, sizeof(PMEMoid) * size, NULL, NULL); if (TOID_IS_NULL(array)) { fprintf(stderr, "POBJ_ALLOC\n"); return OID_NULL; } for (size_t i = 0; i < size; i++) { if (pmemobj_alloc(pop, &D_RW(array)[i], sizeof(struct array_elm), TOID_TYPE_NUM(PMEMoid), elm_constructor, &i)) { fprintf(stderr, "pmemobj_alloc\n"); } } return array.oid; } /* * alloc_toid -- allocate array of TOID(struct array_elm) type */ static PMEMoid alloc_toid(size_t size) { TOID_ARRAY(TOID(struct array_elm)) array; /* * To allocate persistent array of TOID with user-defined structure type * is necessary to allocate pointer with size equal to number of * elements multiplied by size of TOID of proper type and to allocate * each of elements separately. */ POBJ_ALLOC(pop, &array, TOID(struct array_elm), sizeof(TOID(struct array_elm)) * size, NULL, NULL); if (TOID_IS_NULL(array)) { fprintf(stderr, "POBJ_ALLOC\n"); return OID_NULL; } for (size_t i = 0; i < size; i++) { POBJ_NEW(pop, &D_RW(array)[i], struct array_elm, elm_constructor, &i); if (TOID_IS_NULL(D_RW(array)[i])) { fprintf(stderr, "POBJ_ALLOC\n"); assert(0); } } return array.oid; } typedef PMEMoid (*fn_alloc)(size_t size); static fn_alloc alloc_array[] = {NULL, alloc_int, alloc_pmemoid, alloc_toid}; /* * do_print -- print values stored by proper array */ static void do_print(int argc, char *argv[]) { if (argc != 1) { printf("usage: ./array print \n"); return; } TOID(struct array_info) array_info = find_array(argv[0]); if (TOID_IS_NULL(array_info)) { printf("%s doesn't exist\n", argv[0]); return; } printf("%s:\n", argv[0]); print_array[D_RO(array_info)->type](D_RW(array_info)); printf("\n"); } /* * do_free -- de-allocate proper array and proper TOID of array_info type */ static void do_free(int argc, char *argv[]) { if (argc != 1) { printf("usage: ./array free \n"); return; } TOID(struct array_info) array_info = find_array(argv[0]); if (TOID_IS_NULL(array_info)) { printf("%s doesn't exist\n", argv[0]); return; } free_array[D_RO(array_info)->type](D_RW(array_info)); POBJ_FREE(&array_info); } /* * do_realloc -- reallocate proper array to given size and update information * in array_info structure */ static void do_realloc(int argc, char *argv[]) { if (argc != 2) { printf("usage: ./array realloc" " \n"); return; } size_t size = atoi(argv[1]); TOID(struct array_info) array_info = find_array(argv[0]); if (TOID_IS_NULL(array_info)) { printf("%s doesn't exist\n", argv[0]); return; } struct array_info *info = D_RW(array_info); info->array = realloc_array[info->type](&info->array, info->size, size); if (OID_IS_NULL(info->array)) { if (size != 0) printf("POBJ_REALLOC\n"); } info->size = size; pmemobj_persist(pop, info, sizeof(*info)); } /* * do_alloc -- allocate persistent array and TOID of array_info type * and set it with information about new array */ static void do_alloc(int argc, char *argv[]) { if (argc != 3) { printf("usage: ./array alloc " " \n"); return; } enum array_types type = get_type(argv[2]); if (type == UNKNOWN_ARRAY_TYPE) return; size_t size = atoi(argv[1]); TOID(struct array_info) array_info = find_array(argv[0]); if (!TOID_IS_NULL(array_info)) POBJ_FREE(&array_info); POBJ_ZNEW(pop, &array_info, struct array_info); struct array_info *info = D_RW(array_info); strncpy(info->name, argv[0], MAX_BUFFLEN); info->name[MAX_BUFFLEN - 1] = '\0'; info->size = size; info->type = type; info->array = alloc_array[type](size); if (OID_IS_NULL(info->array)) assert(0); pmemobj_persist(pop, info, sizeof(*info)); } typedef void (*fn_op)(int argc, char *argv[]); static fn_op operations[] = {do_alloc, do_realloc, do_free, do_print}; int main(int argc, char *argv[]) { if (argc < 3) { print_usage(); return 1; } const char *path = argv[1]; pop = NULL; if (file_exists(path) != 0) { if ((pop = pmemobj_create(path, POBJ_LAYOUT_NAME(array), PMEMOBJ_MIN_POOL, CREATE_MODE_RW)) == NULL) { printf("failed to create pool\n"); return 1; } } else { if ((pop = pmemobj_open(path, POBJ_LAYOUT_NAME(array))) == NULL) { printf("failed to open pool\n"); return 1; } } const char *option = argv[2]; argv += 3; argc -= 3; const char *names[] = {"alloc", "realloc", "free", "print"}; int i = 0; for (; i < COUNT_OF(names) && strcmp(option, names[i]) != 0; i++); if (i != COUNT_OF(names)) operations[i](argc, argv); else print_usage(); pmemobj_close(pop); return 0; } pmdk-1.4.1/src/examples/libpmemobj/array/array.vcxproj000066400000000000000000000055141331545616200230610ustar00rootroot00000000000000 Debug x64 Release x64 {7264C8F6-73FB-4830-9306-1558D3EAC71B} pmemobj 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest CompileAsCpp pmdk-1.4.1/src/examples/libpmemobj/array/array.vcxproj.filters000066400000000000000000000006421331545616200245250ustar00rootroot00000000000000 {71d04e36-7996-4ae7-84d3-fbad27441817} Source Files pmdk-1.4.1/src/examples/libpmemobj/btree.c000066400000000000000000000122561331545616200204560ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * btree.c -- implementation of persistent binary search tree */ #include #include #include #include #include #include #include POBJ_LAYOUT_BEGIN(btree); POBJ_LAYOUT_ROOT(btree, struct btree); POBJ_LAYOUT_TOID(btree, struct btree_node); POBJ_LAYOUT_END(btree); struct btree_node { int64_t key; TOID(struct btree_node) slots[2]; char value[]; }; struct btree { TOID(struct btree_node) root; }; struct btree_node_arg { size_t size; int64_t key; const char *value; }; /* * btree_node_construct -- constructor of btree node */ static int btree_node_construct(PMEMobjpool *pop, void *ptr, void *arg) { struct btree_node *node = (struct btree_node *)ptr; struct btree_node_arg *a = (struct btree_node_arg *)arg; node->key = a->key; strcpy(node->value, a->value); node->slots[0] = TOID_NULL(struct btree_node); node->slots[1] = TOID_NULL(struct btree_node); pmemobj_persist(pop, node, a->size); return 0; } /* * btree_insert -- inserts new element into the tree */ static void btree_insert(PMEMobjpool *pop, int64_t key, const char *value) { TOID(struct btree) btree = POBJ_ROOT(pop, struct btree); TOID(struct btree_node) *dst = &D_RW(btree)->root; while (!TOID_IS_NULL(*dst)) { dst = &D_RW(*dst)->slots[key > D_RO(*dst)->key]; } struct btree_node_arg args; args.size = sizeof(struct btree_node) + strlen(value) + 1; args.key = key; args.value = value; POBJ_ALLOC(pop, dst, struct btree_node, args.size, btree_node_construct, &args); } /* * btree_find -- searches for key in the tree */ static const char * btree_find(PMEMobjpool *pop, int64_t key) { TOID(struct btree) btree = POBJ_ROOT(pop, struct btree); TOID(struct btree_node) node = D_RO(btree)->root; while (!TOID_IS_NULL(node)) { if (D_RO(node)->key == key) return D_RO(node)->value; else node = D_RO(node)->slots[key > D_RO(node)->key]; } return NULL; } /* * btree_node_print -- prints content of the btree node */ static void btree_node_print(const TOID(struct btree_node) node) { printf("%" PRIu64 " %s\n", D_RO(node)->key, D_RO(node)->value); } /* * btree_foreach -- invoke callback for every node */ static void btree_foreach(PMEMobjpool *pop, const TOID(struct btree_node) node, void(*cb)(const TOID(struct btree_node) node)) { if (TOID_IS_NULL(node)) return; btree_foreach(pop, D_RO(node)->slots[0], cb); cb(node); btree_foreach(pop, D_RO(node)->slots[1], cb); } /* * btree_print -- initiates foreach node print */ static void btree_print(PMEMobjpool *pop) { TOID(struct btree) btree = POBJ_ROOT(pop, struct btree); btree_foreach(pop, D_RO(btree)->root, btree_node_print); } int main(int argc, char *argv[]) { if (argc < 3) { printf("usage: %s file-name [p|i|f] [key] [value] \n", argv[0]); return 1; } const char *path = argv[1]; PMEMobjpool *pop; if (file_exists(path) != 0) { if ((pop = pmemobj_create(path, POBJ_LAYOUT_NAME(btree), PMEMOBJ_MIN_POOL, 0666)) == NULL) { perror("failed to create pool\n"); return 1; } } else { if ((pop = pmemobj_open(path, POBJ_LAYOUT_NAME(btree))) == NULL) { perror("failed to open pool\n"); return 1; } } const char op = argv[2][0]; int64_t key; const char *value; switch (op) { case 'p': btree_print(pop); break; case 'i': key = atoll(argv[3]); value = argv[4]; btree_insert(pop, key, value); break; case 'f': key = atoll(argv[3]); if ((value = btree_find(pop, key)) != NULL) printf("%s\n", value); else printf("not found\n"); break; default: printf("invalid operation\n"); break; } pmemobj_close(pop); return 0; } pmdk-1.4.1/src/examples/libpmemobj/btree.vcxproj000066400000000000000000000054241331545616200217260ustar00rootroot00000000000000 Debug x64 Release x64 {0FB8F0FD-276C-413B-97A8-67ABE0C9043B} pmemobj 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} Application true v140 Application false v140 true $(ProjectDir)..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\LongPath.manifest 4996;4200 CompileAsCpp pmdk-1.4.1/src/examples/libpmemobj/btree.vcxproj.filters000066400000000000000000000006421331545616200233720ustar00rootroot00000000000000 {e8e0c541-b98b-40f3-851f-5460fc7af49e} Source Files pmdk-1.4.1/src/examples/libpmemobj/hashmap/000077500000000000000000000000001331545616200206245ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj/hashmap/Makefile000066400000000000000000000032731331545616200222710ustar00rootroot00000000000000# # Copyright 2015-2017, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # LIBRARIES = hashmap_atomic hashmap_tx LIBS = -lpmemobj include ../../Makefile.inc libhashmap_atomic.o: hashmap_atomic.o libhashmap_tx.o: hashmap_tx.o pmdk-1.4.1/src/examples/libpmemobj/hashmap/README000066400000000000000000000016701331545616200215100ustar00rootroot00000000000000This directory contains an example libraries implemented using libpmemobj. The *hashmap_tx* and *hashmap_atomic* libraries are two implementations of hashmap which utilizes transactional and atomic API of libpmemobj respectively. Both libraries may be used through *mapcli* application located in examples/libpmemobj/map directory. Atomic version, while simpler on the surface, have 2 significant drawbacks: - libpmemobj's list API implements only double-linked lists, which wastes memory here (we don't need to traverse backward) and what is more important: - it needs to handle recovery process after crash/interruption Transactional version implements its own single-linked lists (it's still not memory efficient, because every allocation has significant overhead, so to mitigate it application would have to keep more values in one node) and can get away without any recovery process - every memory transaction is either done in 0% or 100%. pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap.h000066400000000000000000000035041331545616200224200ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HASHMAP_H #define HASHMAP_H /* common API provided by both implementations */ #include #include struct hashmap_args { uint32_t seed; }; enum hashmap_cmd { HASHMAP_CMD_REBUILD, HASHMAP_CMD_DEBUG, }; #endif /* HASHMAP_H */ pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_atomic.c000066400000000000000000000337711331545616200237600ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* integer hash set implementation which uses only atomic APIs */ #include #include #include #include #include #include #include "hashmap_atomic.h" #include "hashmap_internal.h" /* layout definition */ TOID_DECLARE(struct buckets, HASHMAP_ATOMIC_TYPE_OFFSET + 1); TOID_DECLARE(struct entry, HASHMAP_ATOMIC_TYPE_OFFSET + 2); struct entry { uint64_t key; PMEMoid value; /* list pointer */ POBJ_LIST_ENTRY(struct entry) list; }; struct entry_args { uint64_t key; PMEMoid value; }; POBJ_LIST_HEAD(entries_head, struct entry); struct buckets { /* number of buckets */ size_t nbuckets; /* array of lists */ struct entries_head bucket[]; }; struct hashmap_atomic { /* random number generator seed */ uint32_t seed; /* hash function coefficients */ uint32_t hash_fun_a; uint32_t hash_fun_b; uint64_t hash_fun_p; /* number of values inserted */ uint64_t count; /* whether "count" should be updated */ uint32_t count_dirty; /* buckets */ TOID(struct buckets) buckets; /* buckets, used during rehashing, null otherwise */ TOID(struct buckets) buckets_tmp; }; /* * create_entry -- entry initializer */ static int create_entry(PMEMobjpool *pop, void *ptr, void *arg) { struct entry *e = (struct entry *)ptr; struct entry_args *args = (struct entry_args *)arg; e->key = args->key; e->value = args->value; memset(&e->list, 0, sizeof(e->list)); pmemobj_persist(pop, e, sizeof(*e)); return 0; } /* * create_buckets -- buckets initializer */ static int create_buckets(PMEMobjpool *pop, void *ptr, void *arg) { struct buckets *b = (struct buckets *)ptr; b->nbuckets = *((size_t *)arg); pmemobj_memset_persist(pop, &b->bucket, 0, b->nbuckets * sizeof(b->bucket[0])); pmemobj_persist(pop, &b->nbuckets, sizeof(b->nbuckets)); return 0; } /* * create_hashmap -- hashmap initializer */ static void create_hashmap(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint32_t seed) { D_RW(hashmap)->seed = seed; do { D_RW(hashmap)->hash_fun_a = (uint32_t)rand(); } while (D_RW(hashmap)->hash_fun_a == 0); D_RW(hashmap)->hash_fun_b = (uint32_t)rand(); D_RW(hashmap)->hash_fun_p = HASH_FUNC_COEFF_P; size_t len = INIT_BUCKETS_NUM; size_t sz = sizeof(struct buckets) + len * sizeof(struct entries_head); if (POBJ_ALLOC(pop, &D_RW(hashmap)->buckets, struct buckets, sz, create_buckets, &len)) { fprintf(stderr, "root alloc failed: %s\n", pmemobj_errormsg()); abort(); } pmemobj_persist(pop, D_RW(hashmap), sizeof(*D_RW(hashmap))); } /* * hash -- the simplest hashing function, * see https://en.wikipedia.org/wiki/Universal_hashing#Hashing_integers */ static uint64_t hash(const TOID(struct hashmap_atomic) *hashmap, const TOID(struct buckets) *buckets, uint64_t value) { uint32_t a = D_RO(*hashmap)->hash_fun_a; uint32_t b = D_RO(*hashmap)->hash_fun_b; uint64_t p = D_RO(*hashmap)->hash_fun_p; size_t len = D_RO(*buckets)->nbuckets; return ((a * value + b) % p) % len; } /* * hm_atomic_rebuild_finish -- finishes rebuild, assumes buckets_tmp is not null */ static void hm_atomic_rebuild_finish(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap) { TOID(struct buckets) cur = D_RO(hashmap)->buckets; TOID(struct buckets) tmp = D_RO(hashmap)->buckets_tmp; for (size_t i = 0; i < D_RO(cur)->nbuckets; ++i) { while (!POBJ_LIST_EMPTY(&D_RO(cur)->bucket[i])) { TOID(struct entry) en = POBJ_LIST_FIRST(&D_RO(cur)->bucket[i]); uint64_t h = hash(&hashmap, &tmp, D_RO(en)->key); if (POBJ_LIST_MOVE_ELEMENT_HEAD(pop, &D_RW(cur)->bucket[i], &D_RW(tmp)->bucket[h], en, list, list)) { fprintf(stderr, "move failed: %s\n", pmemobj_errormsg()); abort(); } } } POBJ_FREE(&D_RO(hashmap)->buckets); D_RW(hashmap)->buckets = D_RO(hashmap)->buckets_tmp; pmemobj_persist(pop, &D_RW(hashmap)->buckets, sizeof(D_RW(hashmap)->buckets)); /* * We have to set offset manually instead of substituting OID_NULL, * because we won't be able to recover easily if crash happens after * pool_uuid_lo, but before offset is set. Another reason why everyone * should use transaction API. * See recovery process in hm_init and TOID_IS_NULL macro definition. */ D_RW(hashmap)->buckets_tmp.oid.off = 0; pmemobj_persist(pop, &D_RW(hashmap)->buckets_tmp, sizeof(D_RW(hashmap)->buckets_tmp)); } /* * hm_atomic_rebuild -- rebuilds the hashmap with a new number of buckets */ static void hm_atomic_rebuild(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, size_t new_len) { if (new_len == 0) new_len = D_RO(D_RO(hashmap)->buckets)->nbuckets; size_t sz = sizeof(struct buckets) + new_len * sizeof(struct entries_head); POBJ_ALLOC(pop, &D_RW(hashmap)->buckets_tmp, struct buckets, sz, create_buckets, &new_len); if (TOID_IS_NULL(D_RO(hashmap)->buckets_tmp)) { fprintf(stderr, "failed to allocate temporary space of size: %zu" ", %s\n", new_len, pmemobj_errormsg()); return; } hm_atomic_rebuild_finish(pop, hashmap); } /* * hm_atomic_insert -- inserts specified value into the hashmap, * returns: * - 0 if successful, * - 1 if value already existed, * - -1 if something bad happened */ int hm_atomic_insert(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key, PMEMoid value) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); int num = 0; POBJ_LIST_FOREACH(var, &D_RO(buckets)->bucket[h], list) { if (D_RO(var)->key == key) return 1; num++; } D_RW(hashmap)->count_dirty = 1; pmemobj_persist(pop, &D_RW(hashmap)->count_dirty, sizeof(D_RW(hashmap)->count_dirty)); struct entry_args args; args.key = key; args.value = value; PMEMoid oid = POBJ_LIST_INSERT_NEW_HEAD(pop, &D_RW(buckets)->bucket[h], list, sizeof(struct entry), create_entry, &args); if (OID_IS_NULL(oid)) { fprintf(stderr, "failed to allocate entry: %s\n", pmemobj_errormsg()); return -1; } D_RW(hashmap)->count++; pmemobj_persist(pop, &D_RW(hashmap)->count, sizeof(D_RW(hashmap)->count)); D_RW(hashmap)->count_dirty = 0; pmemobj_persist(pop, &D_RW(hashmap)->count_dirty, sizeof(D_RW(hashmap)->count_dirty)); num++; if (num > MAX_HASHSET_THRESHOLD || (num > MIN_HASHSET_THRESHOLD && D_RO(hashmap)->count > 2 * D_RO(buckets)->nbuckets)) hm_atomic_rebuild(pop, hashmap, D_RW(buckets)->nbuckets * 2); return 0; } /* * hm_atomic_remove -- removes specified value from the hashmap, * returns: * - 1 if successful, * - 0 if value didn't exist, * - -1 if something bad happened */ PMEMoid hm_atomic_remove(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); POBJ_LIST_FOREACH(var, &D_RW(buckets)->bucket[h], list) { if (D_RO(var)->key == key) break; } if (TOID_IS_NULL(var)) return OID_NULL; D_RW(hashmap)->count_dirty = 1; pmemobj_persist(pop, &D_RW(hashmap)->count_dirty, sizeof(D_RW(hashmap)->count_dirty)); if (POBJ_LIST_REMOVE_FREE(pop, &D_RW(buckets)->bucket[h], var, list)) { fprintf(stderr, "list remove failed: %s\n", pmemobj_errormsg()); return OID_NULL; } D_RW(hashmap)->count--; pmemobj_persist(pop, &D_RW(hashmap)->count, sizeof(D_RW(hashmap)->count)); D_RW(hashmap)->count_dirty = 0; pmemobj_persist(pop, &D_RW(hashmap)->count_dirty, sizeof(D_RW(hashmap)->count_dirty)); if (D_RO(hashmap)->count < D_RO(buckets)->nbuckets) hm_atomic_rebuild(pop, hashmap, D_RO(buckets)->nbuckets / 2); return D_RO(var)->value; } /* * hm_atomic_foreach -- prints all values from the hashmap */ int hm_atomic_foreach(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, int (*cb)(uint64_t key, PMEMoid value, void *arg), void *arg) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; int ret = 0; for (size_t i = 0; i < D_RO(buckets)->nbuckets; ++i) POBJ_LIST_FOREACH(var, &D_RO(buckets)->bucket[i], list) { ret = cb(D_RO(var)->key, D_RO(var)->value, arg); if (ret) return ret; } return 0; } /* * hm_atomic_debug -- prints complete hashmap state */ static void hm_atomic_debug(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, FILE *out) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; fprintf(out, "a: %u b: %u p: %" PRIu64 "\n", D_RO(hashmap)->hash_fun_a, D_RO(hashmap)->hash_fun_b, D_RO(hashmap)->hash_fun_p); fprintf(out, "count: %" PRIu64 ", buckets: %zu\n", D_RO(hashmap)->count, D_RO(buckets)->nbuckets); for (size_t i = 0; i < D_RO(buckets)->nbuckets; ++i) { if (POBJ_LIST_EMPTY(&D_RO(buckets)->bucket[i])) continue; int num = 0; fprintf(out, "%zu: ", i); POBJ_LIST_FOREACH(var, &D_RO(buckets)->bucket[i], list) { fprintf(out, "%" PRIu64 " ", D_RO(var)->key); num++; } fprintf(out, "(%d)\n", num); } } /* * hm_atomic_get -- checks whether specified value is in the hashmap */ PMEMoid hm_atomic_get(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); POBJ_LIST_FOREACH(var, &D_RO(buckets)->bucket[h], list) if (D_RO(var)->key == key) return D_RO(var)->value; return OID_NULL; } /* * hm_atomic_lookup -- checks whether specified value is in the hashmap */ int hm_atomic_lookup(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); POBJ_LIST_FOREACH(var, &D_RO(buckets)->bucket[h], list) if (D_RO(var)->key == key) return 1; return 0; } /* * hm_atomic_create -- initializes hashmap state, called after pmemobj_create */ int hm_atomic_create(PMEMobjpool *pop, TOID(struct hashmap_atomic) *map, void *arg) { struct hashmap_args *args = (struct hashmap_args *)arg; uint32_t seed = args ? args->seed : 0; POBJ_ZNEW(pop, map, struct hashmap_atomic); create_hashmap(pop, *map, seed); return 0; } /* * hm_atomic_init -- recovers hashmap state, called after pmemobj_open */ int hm_atomic_init(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap) { srand(D_RO(hashmap)->seed); /* handle rebuild interruption */ if (!TOID_IS_NULL(D_RO(hashmap)->buckets_tmp)) { printf("rebuild, previous attempt crashed\n"); if (TOID_EQUALS(D_RO(hashmap)->buckets, D_RO(hashmap)->buckets_tmp)) { /* see comment in hm_rebuild_finish */ D_RW(hashmap)->buckets_tmp.oid.off = 0; pmemobj_persist(pop, &D_RW(hashmap)->buckets_tmp, sizeof(D_RW(hashmap)->buckets_tmp)); } else if (TOID_IS_NULL(D_RW(hashmap)->buckets)) { D_RW(hashmap)->buckets = D_RW(hashmap)->buckets_tmp; pmemobj_persist(pop, &D_RW(hashmap)->buckets, sizeof(D_RW(hashmap)->buckets)); /* see comment in hm_rebuild_finish */ D_RW(hashmap)->buckets_tmp.oid.off = 0; pmemobj_persist(pop, &D_RW(hashmap)->buckets_tmp, sizeof(D_RW(hashmap)->buckets_tmp)); } else { hm_atomic_rebuild_finish(pop, hashmap); } } /* handle insert or remove interruption */ if (D_RO(hashmap)->count_dirty) { printf("count dirty, recalculating\n"); TOID(struct entry) var; TOID(struct buckets) buckets = D_RO(hashmap)->buckets; uint64_t cnt = 0; for (size_t i = 0; i < D_RO(buckets)->nbuckets; ++i) POBJ_LIST_FOREACH(var, &D_RO(buckets)->bucket[i], list) cnt++; printf("old count: %" PRIu64 ", new count: %" PRIu64 "\n", D_RO(hashmap)->count, cnt); D_RW(hashmap)->count = cnt; pmemobj_persist(pop, &D_RW(hashmap)->count, sizeof(D_RW(hashmap)->count)); D_RW(hashmap)->count_dirty = 0; pmemobj_persist(pop, &D_RW(hashmap)->count_dirty, sizeof(D_RW(hashmap)->count_dirty)); } return 0; } /* * hm_atomic_check -- checks if specified persistent object is an * instance of hashmap */ int hm_atomic_check(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap) { return TOID_IS_NULL(hashmap) || !TOID_VALID(hashmap); } /* * hm_atomic_count -- returns number of elements */ size_t hm_atomic_count(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap) { return D_RO(hashmap)->count; } /* * hm_atomic_cmd -- execute cmd for hashmap */ int hm_atomic_cmd(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, unsigned cmd, uint64_t arg) { switch (cmd) { case HASHMAP_CMD_REBUILD: hm_atomic_rebuild(pop, hashmap, arg); return 0; case HASHMAP_CMD_DEBUG: if (!arg) return -EINVAL; hm_atomic_debug(pop, hashmap, (FILE *)arg); return 0; default: return -EINVAL; } } pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_atomic.h000066400000000000000000000055231331545616200237570ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HASHMAP_ATOMIC_H #define HASHMAP_ATOMIC_H #include #include #include #include #ifndef HASHMAP_ATOMIC_TYPE_OFFSET #define HASHMAP_ATOMIC_TYPE_OFFSET 1000 #endif struct hashmap_atomic; TOID_DECLARE(struct hashmap_atomic, HASHMAP_ATOMIC_TYPE_OFFSET + 0); int hm_atomic_check(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap); int hm_atomic_create(PMEMobjpool *pop, TOID(struct hashmap_atomic) *map, void *arg); int hm_atomic_init(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap); int hm_atomic_insert(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key, PMEMoid value); PMEMoid hm_atomic_remove(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key); PMEMoid hm_atomic_get(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key); int hm_atomic_lookup(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, uint64_t key); int hm_atomic_foreach(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, int (*cb)(uint64_t key, PMEMoid value, void *arg), void *arg); size_t hm_atomic_count(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap); int hm_atomic_cmd(PMEMobjpool *pop, TOID(struct hashmap_atomic) hashmap, unsigned cmd, uint64_t arg); #endif /* HASHMAP_ATOMIC_H */ pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_atomic.vcxproj000066400000000000000000000057241331545616200252260ustar00rootroot00000000000000 Debug x64 Release x64 {F5E2F6C4-19BA-497A-B754-232E469BE647} pmemobj 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} StaticLibrary true v140 StaticLibrary false v140 true .;$(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest CompileAsCpp 4200;4996 pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_atomic.vcxproj.filters000066400000000000000000000015471331545616200266740ustar00rootroot00000000000000 {58d06973-b76f-41b5-ab03-4e50a98436be} {5e7e56b2-b3d3-4d53-bbd1-95e962111077} Source Files Header Files Header Files Header Files pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_internal.h000066400000000000000000000037641331545616200243240ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HASHSET_INTERNAL_H #define HASHSET_INTERNAL_H /* large prime number used as a hashing function coefficient */ #define HASH_FUNC_COEFF_P 32212254719ULL /* initial number of buckets */ #define INIT_BUCKETS_NUM 10 /* number of values in a bucket which trigger hashtable rebuild check */ #define MIN_HASHSET_THRESHOLD 5 /* number of values in a bucket which force hashtable rebuild */ #define MAX_HASHSET_THRESHOLD 10 #endif pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_tx.c000066400000000000000000000256561331545616200231420ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* integer hash set implementation which uses only transaction APIs */ #include #include #include #include #include #include "hashmap_tx.h" #include "hashmap_internal.h" /* layout definition */ TOID_DECLARE(struct buckets, HASHMAP_TX_TYPE_OFFSET + 1); TOID_DECLARE(struct entry, HASHMAP_TX_TYPE_OFFSET + 2); struct entry { uint64_t key; PMEMoid value; /* next entry list pointer */ TOID(struct entry) next; }; struct buckets { /* number of buckets */ size_t nbuckets; /* array of lists */ TOID(struct entry) bucket[]; }; struct hashmap_tx { /* random number generator seed */ uint32_t seed; /* hash function coefficients */ uint32_t hash_fun_a; uint32_t hash_fun_b; uint64_t hash_fun_p; /* number of values inserted */ uint64_t count; /* buckets */ TOID(struct buckets) buckets; }; /* * create_hashmap -- hashmap initializer */ static void create_hashmap(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint32_t seed) { size_t len = INIT_BUCKETS_NUM; size_t sz = sizeof(struct buckets) + len * sizeof(TOID(struct entry)); TX_BEGIN(pop) { TX_ADD(hashmap); D_RW(hashmap)->seed = seed; do { D_RW(hashmap)->hash_fun_a = (uint32_t)rand(); } while (D_RW(hashmap)->hash_fun_a == 0); D_RW(hashmap)->hash_fun_b = (uint32_t)rand(); D_RW(hashmap)->hash_fun_p = HASH_FUNC_COEFF_P; D_RW(hashmap)->buckets = TX_ZALLOC(struct buckets, sz); D_RW(D_RW(hashmap)->buckets)->nbuckets = len; } TX_ONABORT { fprintf(stderr, "%s: transaction aborted: %s\n", __func__, pmemobj_errormsg()); abort(); } TX_END } /* * hash -- the simplest hashing function, * see https://en.wikipedia.org/wiki/Universal_hashing#Hashing_integers */ static uint64_t hash(const TOID(struct hashmap_tx) *hashmap, const TOID(struct buckets) *buckets, uint64_t value) { uint32_t a = D_RO(*hashmap)->hash_fun_a; uint32_t b = D_RO(*hashmap)->hash_fun_b; uint64_t p = D_RO(*hashmap)->hash_fun_p; size_t len = D_RO(*buckets)->nbuckets; return ((a * value + b) % p) % len; } /* * hm_tx_rebuild -- rebuilds the hashmap with a new number of buckets */ static void hm_tx_rebuild(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, size_t new_len) { TOID(struct buckets) buckets_old = D_RO(hashmap)->buckets; if (new_len == 0) new_len = D_RO(buckets_old)->nbuckets; size_t sz_old = sizeof(struct buckets) + D_RO(buckets_old)->nbuckets * sizeof(TOID(struct entry)); size_t sz_new = sizeof(struct buckets) + new_len * sizeof(TOID(struct entry)); TX_BEGIN(pop) { TX_ADD_FIELD(hashmap, buckets); TOID(struct buckets) buckets_new = TX_ZALLOC(struct buckets, sz_new); D_RW(buckets_new)->nbuckets = new_len; pmemobj_tx_add_range(buckets_old.oid, 0, sz_old); for (size_t i = 0; i < D_RO(buckets_old)->nbuckets; ++i) { while (!TOID_IS_NULL(D_RO(buckets_old)->bucket[i])) { TOID(struct entry) en = D_RO(buckets_old)->bucket[i]; uint64_t h = hash(&hashmap, &buckets_new, D_RO(en)->key); D_RW(buckets_old)->bucket[i] = D_RO(en)->next; TX_ADD_FIELD(en, next); D_RW(en)->next = D_RO(buckets_new)->bucket[h]; D_RW(buckets_new)->bucket[h] = en; } } D_RW(hashmap)->buckets = buckets_new; TX_FREE(buckets_old); } TX_ONABORT { fprintf(stderr, "%s: transaction aborted: %s\n", __func__, pmemobj_errormsg()); /* * We don't need to do anything here, because everything is * consistent. The only thing affected is performance. */ } TX_END } /* * hm_tx_insert -- inserts specified value into the hashmap, * returns: * - 0 if successful, * - 1 if value already existed, * - -1 if something bad happened */ int hm_tx_insert(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key, PMEMoid value) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); int num = 0; for (var = D_RO(buckets)->bucket[h]; !TOID_IS_NULL(var); var = D_RO(var)->next) { if (D_RO(var)->key == key) return 1; num++; } int ret = 0; TX_BEGIN(pop) { TX_ADD_FIELD(D_RO(hashmap)->buckets, bucket[h]); TX_ADD_FIELD(hashmap, count); TOID(struct entry) e = TX_NEW(struct entry); D_RW(e)->key = key; D_RW(e)->value = value; D_RW(e)->next = D_RO(buckets)->bucket[h]; D_RW(buckets)->bucket[h] = e; D_RW(hashmap)->count++; num++; } TX_ONABORT { fprintf(stderr, "transaction aborted: %s\n", pmemobj_errormsg()); ret = -1; } TX_END if (ret) return ret; if (num > MAX_HASHSET_THRESHOLD || (num > MIN_HASHSET_THRESHOLD && D_RO(hashmap)->count > 2 * D_RO(buckets)->nbuckets)) hm_tx_rebuild(pop, hashmap, D_RO(buckets)->nbuckets * 2); return 0; } /* * hm_tx_remove -- removes specified value from the hashmap, * returns: * - key's value if successful, * - OID_NULL if value didn't exist or if something bad happened */ PMEMoid hm_tx_remove(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var, prev = TOID_NULL(struct entry); uint64_t h = hash(&hashmap, &buckets, key); for (var = D_RO(buckets)->bucket[h]; !TOID_IS_NULL(var); prev = var, var = D_RO(var)->next) { if (D_RO(var)->key == key) break; } if (TOID_IS_NULL(var)) return OID_NULL; int ret = 0; TX_BEGIN(pop) { if (TOID_IS_NULL(prev)) TX_ADD_FIELD(D_RO(hashmap)->buckets, bucket[h]); else TX_ADD_FIELD(prev, next); TX_ADD_FIELD(hashmap, count); if (TOID_IS_NULL(prev)) D_RW(buckets)->bucket[h] = D_RO(var)->next; else D_RW(prev)->next = D_RO(var)->next; D_RW(hashmap)->count--; TX_FREE(var); } TX_ONABORT { fprintf(stderr, "transaction aborted: %s\n", pmemobj_errormsg()); ret = -1; } TX_END if (ret) return OID_NULL; if (D_RO(hashmap)->count < D_RO(buckets)->nbuckets) hm_tx_rebuild(pop, hashmap, D_RO(buckets)->nbuckets / 2); return D_RO(var)->value; } /* * hm_tx_foreach -- prints all values from the hashmap */ int hm_tx_foreach(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, int (*cb)(uint64_t key, PMEMoid value, void *arg), void *arg) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; int ret = 0; for (size_t i = 0; i < D_RO(buckets)->nbuckets; ++i) { if (TOID_IS_NULL(D_RO(buckets)->bucket[i])) continue; for (var = D_RO(buckets)->bucket[i]; !TOID_IS_NULL(var); var = D_RO(var)->next) { ret = cb(D_RO(var)->key, D_RO(var)->value, arg); if (ret) break; } } return ret; } /* * hm_tx_debug -- prints complete hashmap state */ static void hm_tx_debug(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, FILE *out) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; fprintf(out, "a: %u b: %u p: %" PRIu64 "\n", D_RO(hashmap)->hash_fun_a, D_RO(hashmap)->hash_fun_b, D_RO(hashmap)->hash_fun_p); fprintf(out, "count: %" PRIu64 ", buckets: %zu\n", D_RO(hashmap)->count, D_RO(buckets)->nbuckets); for (size_t i = 0; i < D_RO(buckets)->nbuckets; ++i) { if (TOID_IS_NULL(D_RO(buckets)->bucket[i])) continue; int num = 0; fprintf(out, "%zu: ", i); for (var = D_RO(buckets)->bucket[i]; !TOID_IS_NULL(var); var = D_RO(var)->next) { fprintf(out, "%" PRIu64 " ", D_RO(var)->key); num++; } fprintf(out, "(%d)\n", num); } } /* * hm_tx_get -- checks whether specified value is in the hashmap */ PMEMoid hm_tx_get(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); for (var = D_RO(buckets)->bucket[h]; !TOID_IS_NULL(var); var = D_RO(var)->next) if (D_RO(var)->key == key) return D_RO(var)->value; return OID_NULL; } /* * hm_tx_lookup -- checks whether specified value exists */ int hm_tx_lookup(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key) { TOID(struct buckets) buckets = D_RO(hashmap)->buckets; TOID(struct entry) var; uint64_t h = hash(&hashmap, &buckets, key); for (var = D_RO(buckets)->bucket[h]; !TOID_IS_NULL(var); var = D_RO(var)->next) if (D_RO(var)->key == key) return 1; return 0; } /* * hm_tx_count -- returns number of elements */ size_t hm_tx_count(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap) { return D_RO(hashmap)->count; } /* * hm_tx_init -- recovers hashmap state, called after pmemobj_open */ int hm_tx_init(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap) { srand(D_RO(hashmap)->seed); return 0; } /* * hm_tx_create -- allocates new hashmap */ int hm_tx_create(PMEMobjpool *pop, TOID(struct hashmap_tx) *map, void *arg) { struct hashmap_args *args = (struct hashmap_args *)arg; int ret = 0; TX_BEGIN(pop) { TX_ADD_DIRECT(map); *map = TX_ZNEW(struct hashmap_tx); uint32_t seed = args ? args->seed : 0; create_hashmap(pop, *map, seed); } TX_ONABORT { ret = -1; } TX_END return ret; } /* * hm_tx_check -- checks if specified persistent object is an * instance of hashmap */ int hm_tx_check(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap) { return TOID_IS_NULL(hashmap) || !TOID_VALID(hashmap); } /* * hm_tx_cmd -- execute cmd for hashmap */ int hm_tx_cmd(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, unsigned cmd, uint64_t arg) { switch (cmd) { case HASHMAP_CMD_REBUILD: hm_tx_rebuild(pop, hashmap, arg); return 0; case HASHMAP_CMD_DEBUG: if (!arg) return -EINVAL; hm_tx_debug(pop, hashmap, (FILE *)arg); return 0; default: return -EINVAL; } } pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_tx.h000066400000000000000000000053411331545616200231340ustar00rootroot00000000000000/* * Copyright 2015-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HASHMAP_TX_H #define HASHMAP_TX_H #include #include #include #include #ifndef HASHMAP_TX_TYPE_OFFSET #define HASHMAP_TX_TYPE_OFFSET 1004 #endif struct hashmap_tx; TOID_DECLARE(struct hashmap_tx, HASHMAP_TX_TYPE_OFFSET + 0); int hm_tx_check(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap); int hm_tx_create(PMEMobjpool *pop, TOID(struct hashmap_tx) *map, void *arg); int hm_tx_init(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap); int hm_tx_insert(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key, PMEMoid value); PMEMoid hm_tx_remove(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key); PMEMoid hm_tx_get(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key); int hm_tx_lookup(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, uint64_t key); int hm_tx_foreach(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, int (*cb)(uint64_t key, PMEMoid value, void *arg), void *arg); size_t hm_tx_count(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap); int hm_tx_cmd(PMEMobjpool *pop, TOID(struct hashmap_tx) hashmap, unsigned cmd, uint64_t arg); #endif /* HASHMAP_TX_H */ pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_tx.vcxproj000066400000000000000000000057141331545616200244040ustar00rootroot00000000000000 Debug x64 Release x64 {D93A2683-6D99-4F18-B378-91195D23E007} pmemobj 10.0.14393.0 {1baa1617-93ae-4196-8a1a-bd492fb18aef} {9e9e3d25-2139-4a5d-9200-18148ddead45} StaticLibrary true v140 StaticLibrary false v140 true .;$(ProjectDir)..\..\;$(solutionDir)include;$(IncludePath);$(WindowsSDK_IncludePath); ..\..\..\LongPath.manifest CompileAsCpp 4200;4996 pmdk-1.4.1/src/examples/libpmemobj/hashmap/hashmap_tx.vcxproj.filters000066400000000000000000000015371331545616200260520ustar00rootroot00000000000000 Header Files Header Files Header Files {b0b832cc-e298-40a8-aa01-9c935ebf8393} {62513d1d-c5c7-4d25-9ecb-60cf10a23132} Source Files pmdk-1.4.1/src/examples/libpmemobj/libart/000077500000000000000000000000001331545616200204605ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj/libart/.gitignore000066400000000000000000000000301331545616200224410ustar00rootroot00000000000000arttree examine_arttree pmdk-1.4.1/src/examples/libpmemobj/libart/Makefile000066400000000000000000000046471331545616200221330ustar00rootroot00000000000000# # Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH # Copyright 2016-2018, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # # =========================================================================== # # Filename: Makefile # # Description: build libart port to libpmemobj # # Author: Andreas Bluemle, Dieter Kasper # Andreas.Bluemle.external@ts.fujitsu.com # dieter.kasper@ts.fujitsu.com # # Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH # # =========================================================================== # include ../../../common.inc ARCH := $(call get_arch) ifeq ($(ARCH), x86_64) # libart uses x86 intrinsics PROGS = arttree examine_arttree LIBRARIES = art endif LIBS = -lpmemobj include ../../Makefile.inc $(PROGS): | $(DYNAMIC_LIBRARIES) $(PROGS): LDFLAGS += -Wl,-rpath=. -L. -lart libart.o: art.o arttree: arttree.o examine_arttree: arttree_structures.o arttree_examine.o arttree_search.o pmdk-1.4.1/src/examples/libpmemobj/libart/art.c000066400000000000000000001126221331545616200214160ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2012, Armon Dadgar. All rights reserved. * Copyright 2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: art.c * * Description: implement ART tree using libpmemobj based on libart * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * ============================================================================ */ /* * based on https://github.com/armon/libart/src/art.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libpmemobj.h" #include "art.h" TOID(var_string) null_var_string; TOID(art_leaf) null_art_leaf; TOID(art_node_u) null_art_node_u; int art_tree_init(PMEMobjpool *pop, int *newpool); TOID(art_node_u) make_leaf(PMEMobjpool *pop, const unsigned char *key, int key_len, void *value, int val_len); int fill_leaf(PMEMobjpool *pop, TOID(art_leaf) al, const unsigned char *key, int key_len, void *value, int val_len); TOID(art_node_u) alloc_node(PMEMobjpool *pop, art_node_type node_type); TOID(var_string) art_insert(PMEMobjpool *pop, const unsigned char *key, int key_len, void *value, int val_len); TOID(var_string) art_delete(PMEMobjpool *pop, const unsigned char *key, int key_len); static TOID(var_string) recursive_insert(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, const unsigned char *key, int key_len, void *value, int val_len, int depth, int *old_val); static TOID(art_leaf) recursive_delete(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, const unsigned char *key, int key_len, int depth); static int leaf_matches(TOID(art_leaf) n, const unsigned char *key, int key_len, int depth); static int longest_common_prefix(TOID(art_leaf) l1, TOID(art_leaf) l2, int depth); static int prefix_mismatch(TOID(art_node_u) n, unsigned char *key, int key_len, int depth); #ifdef LIBART_ITER_PREFIX static int leaf_prefix_matches(TOID(art_leaf) n, const unsigned char *prefix, int prefix_len); #endif static TOID(art_leaf) minimum(TOID(art_node_u) n_u); static TOID(art_leaf) maximum(TOID(art_node_u) n_u); static void copy_header(art_node *dest, art_node *src); static void add_child(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child); static void add_child4(PMEMobjpool *pop, TOID(art_node4) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child); static void add_child16(PMEMobjpool *pop, TOID(art_node16) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child); static void add_child48(PMEMobjpool *pop, TOID(art_node48) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child); static void add_child256(PMEMobjpool *pop, TOID(art_node256) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child); static void remove_child(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) *l); static void remove_child4(PMEMobjpool *pop, TOID(art_node4) n, TOID(art_node_u) *ref, TOID(art_node_u) *l); static void remove_child16(PMEMobjpool *pop, TOID(art_node16) n, TOID(art_node_u) *ref, TOID(art_node_u) *l); static void remove_child48(PMEMobjpool *pop, TOID(art_node48) n, TOID(art_node_u) *ref, unsigned char c); static void remove_child256(PMEMobjpool *pop, TOID(art_node256) n, TOID(art_node_u) *ref, unsigned char c); static TOID(art_node_u)* find_child(TOID(art_node_u) n, unsigned char c); static int check_prefix(const art_node *n, const unsigned char *key, int key_len, int depth); static int leaf_matches(TOID(art_leaf) n, const unsigned char *key, int key_len, int depth); TOID(art_leaf) art_minimum(TOID(struct art_tree_root) t); TOID(art_leaf) art_maximum(TOID(struct art_tree_root) t); #if 0 static void destroy_node(TOID(art_node_u) n_u); #endif int art_iter(PMEMobjpool *pop, art_callback cb, void *data); static void PMEMOIDcopy(PMEMoid *dest, const PMEMoid *src, const int n); static void PMEMOIDmove(PMEMoid *dest, PMEMoid *src, const int n); static void PMEMOIDcopy(PMEMoid *dest, const PMEMoid *src, const int n) { int i; for (i = 0; i < n; i++) { dest[i] = src[i]; } } static void PMEMOIDmove(PMEMoid *dest, PMEMoid *src, const int n) { int i; if (dest > src) { for (i = n - 1; i >= 0; i--) { dest[i] = src[i]; } } else { for (i = 0; i < n; i++) { dest[i] = src[i]; } } } TOID(art_node_u) alloc_node(PMEMobjpool *pop, art_node_type node_type) { TOID(art_node_u) node; TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; TOID(art_leaf) al; node = TX_ZNEW(art_node_u); D_RW(node)->art_node_type = (uint8_t)node_type; switch (node_type) { case NODE4: an4 = TX_ZNEW(art_node4); D_RW(node)->u.an4 = an4; break; case NODE16: an16 = TX_ZNEW(art_node16); D_RW(node)->u.an16 = an16; break; case NODE48: an48 = TX_ZNEW(art_node48); D_RW(node)->u.an48 = an48; break; case NODE256: an256 = TX_ZNEW(art_node256); D_RW(node)->u.an256 = an256; break; case art_leaf_t: al = TX_ZNEW(art_leaf); D_RW(node)->u.al = al; break; default: /* invalid node type */ D_RW(node)->art_node_type = (uint8_t)art_node_types; break; } return node; } int art_tree_init(PMEMobjpool *pop, int *newpool) { int errors = 0; TOID(struct art_tree_root) root; if (pop == NULL) { errors++; } null_var_string.oid = OID_NULL; null_art_leaf.oid = OID_NULL; null_art_node_u.oid = OID_NULL; if (!errors) { TX_BEGIN(pop) { root = POBJ_ROOT(pop, struct art_tree_root); if (*newpool) { TX_ADD(root); D_RW(root)->root.oid = OID_NULL; D_RW(root)->size = 0; *newpool = 0; } } TX_END } return errors; } #if 0 // Recursively destroys the tree static void destroy_node(TOID(art_node_u) n_u) { // Break if null if (TOID_IS_NULL(n_u)) return; // Special case leafs if (IS_LEAF(D_RO(n_u))) { TX_FREE(n_u); return; } // Handle each node type int i; TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; switch (D_RO(n_u)->art_node_type) { case NODE4: an4 = D_RO(n_u)->u.an4; for (i = 0; i < D_RO(an4)->n.num_children; i++) { destroy_node(D_RW(an4)->children[i]); } break; case NODE16: an16 = D_RO(n_u)->u.an16; for (i = 0; i < D_RO(an16)->n.num_children; i++) { destroy_node(D_RW(an16)->children[i]); } break; case NODE48: an48 = D_RO(n_u)->u.an48; for (i = 0; i < D_RO(an48)->n.num_children; i++) { destroy_node(D_RW(an48)->children[i]); } break; case NODE256: an256 = D_RO(n_u)->u.an256; for (i = 0; i < D_RO(an256)->n.num_children; i++) { if (!(TOID_IS_NULL(D_RO(an256)->children[i]))) { destroy_node(D_RW(an256)->children[i]); } } break; default: abort(); } // Free ourself on the way up TX_FREE(n_u); } /* * Destroys an ART tree * @return 0 on success. */ static int art_tree_destroy(TOID(struct art_tree_root) t) { destroy_node(D_RO(t)->root); return 0; } #endif static TOID(art_node_u)* find_child(TOID(art_node_u) n, unsigned char c) { int i; int mask; int bitfield; TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; switch (D_RO(n)->art_node_type) { case NODE4: an4 = D_RO(n)->u.an4; for (i = 0; i < D_RO(an4)->n.num_children; i++) { if (D_RO(an4)->keys[i] == c) { return &(D_RW(an4)->children[i]); } } break; case NODE16: { __m128i cmp; an16 = D_RO(n)->u.an16; // Compare the key to all 16 stored keys cmp = _mm_cmpeq_epi8(_mm_set1_epi8(c), _mm_loadu_si128((__m128i *)D_RO(an16)->keys)); // Use a mask to ignore children that don't exist mask = (1 << D_RO(an16)->n.num_children) - 1; bitfield = _mm_movemask_epi8(cmp) & mask; /* * If we have a match (any bit set) then we can * return the pointer match using ctz to get the index. */ if (bitfield) { return &(D_RW(an16)->children[__builtin_ctz(bitfield)]); } break; } case NODE48: an48 = D_RO(n)->u.an48; i = D_RO(an48)->keys[c]; if (i) { return &(D_RW(an48)->children[i - 1]); } break; case NODE256: an256 = D_RO(n)->u.an256; if (!TOID_IS_NULL(D_RO(an256)->children[c])) { return &(D_RW(an256)->children[c]); } break; default: abort(); } return &null_art_node_u; } static inline int min(int a, int b) { return (a < b) ? a : b; } /* * Returns the number of prefix characters shared between * the key and node. */ static int check_prefix(const art_node *n, const unsigned char *key, int key_len, int depth) { int max_cmp = min(min(n->partial_len, MAX_PREFIX_LEN), key_len - depth); int idx; for (idx = 0; idx < max_cmp; idx++) { if (n->partial[idx] != key[depth + idx]) return idx; } return idx; } /* * Checks if a leaf matches * @return 0 on success. */ static int leaf_matches(TOID(art_leaf) n, const unsigned char *key, int key_len, int depth) { (void) depth; // Fail if the key lengths are different if (D_RO(D_RO(n)->key)->len != (uint32_t)key_len) return 1; // Compare the keys starting at the depth return memcmp(D_RO(D_RO(n)->key)->s, key, key_len); } /* * Searches for a value in the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @return NULL if the item was not found, otherwise * the value pointer is returned. */ TOID(var_string) art_search(PMEMobjpool *pop, const unsigned char *key, int key_len) { TOID(struct art_tree_root)t = POBJ_ROOT(pop, struct art_tree_root); TOID(art_node_u) *child; TOID(art_node_u) n = D_RO(t)->root; const art_node *n_an; int prefix_len; int depth = 0; while (!TOID_IS_NULL(n)) { // Might be a leaf if (IS_LEAF(D_RO(n))) { // n = LEAF_RAW(n); // Check if the expanded path matches if (!leaf_matches(D_RO(n)->u.al, key, key_len, depth)) { return (D_RO(D_RO(n)->u.al))->value; } return null_var_string; } switch (D_RO(n)->art_node_type) { case NODE4: n_an = &(D_RO(D_RO(n)->u.an4)->n); break; case NODE16: n_an = &(D_RO(D_RO(n)->u.an16)->n); break; case NODE48: n_an = &(D_RO(D_RO(n)->u.an48)->n); break; case NODE256: n_an = &(D_RO(D_RO(n)->u.an256)->n); break; default: return null_var_string; } // Bail if the prefix does not match if (n_an->partial_len) { prefix_len = check_prefix(n_an, key, key_len, depth); if (prefix_len != min(MAX_PREFIX_LEN, n_an->partial_len)) return null_var_string; depth = depth + n_an->partial_len; } // Recursively search child = find_child(n, key[depth]); if (TOID_IS_NULL(*child)) { n.oid = OID_NULL; } else { n = *child; } depth++; } return null_var_string; } // Find the minimum leaf under a node static TOID(art_leaf) minimum(TOID(art_node_u) n_u) { TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; // Handle base cases if (TOID_IS_NULL(n_u)) return null_art_leaf; if (IS_LEAF(D_RO(n_u))) return D_RO(n_u)->u.al; int idx; switch (D_RO(n_u)->art_node_type) { case NODE4: an4 = D_RO(n_u)->u.an4; return minimum(D_RO(an4)->children[0]); case NODE16: an16 = D_RO(n_u)->u.an16; return minimum(D_RO(an16)->children[0]); case NODE48: an48 = D_RO(n_u)->u.an48; idx = 0; while (!(D_RO(an48)->keys[idx])) idx++; idx = D_RO(an48)->keys[idx] - 1; assert(idx < 48); return minimum(D_RO(an48)->children[idx]); case NODE256: an256 = D_RO(n_u)->u.an256; idx = 0; while (!(TOID_IS_NULL(D_RO(an256)->children[idx]))) idx++; return minimum(D_RO(an256)->children[idx]); default: abort(); } } // Find the maximum leaf under a node static TOID(art_leaf) maximum(TOID(art_node_u) n_u) { TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; const art_node *n_an; // Handle base cases if (TOID_IS_NULL(n_u)) return null_art_leaf; if (IS_LEAF(D_RO(n_u))) return D_RO(n_u)->u.al; int idx; switch (D_RO(n_u)->art_node_type) { case NODE4: an4 = D_RO(n_u)->u.an4; n_an = &(D_RO(an4)->n); return maximum(D_RO(an4)->children[n_an->num_children - 1]); case NODE16: an16 = D_RO(n_u)->u.an16; n_an = &(D_RO(an16)->n); return maximum(D_RO(an16)->children[n_an->num_children - 1]); case NODE48: an48 = D_RO(n_u)->u.an48; idx = 255; while (!(D_RO(an48)->keys[idx])) idx--; idx = D_RO(an48)->keys[idx] - 1; assert((idx >= 0) && (idx < 48)); return maximum(D_RO(an48)->children[idx]); case NODE256: an256 = D_RO(n_u)->u.an256; idx = 255; while (!(TOID_IS_NULL(D_RO(an256)->children[idx]))) idx--; return maximum(D_RO(an256)->children[idx]); default: abort(); } } /* * Returns the minimum valued leaf */ TOID(art_leaf) art_minimum(TOID(struct art_tree_root) t) { return minimum(D_RO(t)->root); } /* * Returns the maximum valued leaf */ TOID(art_leaf) art_maximum(TOID(struct art_tree_root) t) { return maximum(D_RO(t)->root); } TOID(art_node_u) make_leaf(PMEMobjpool *pop, const unsigned char *key, int key_len, void *value, int val_len) { TOID(art_node_u)newleaf; newleaf = alloc_node(pop, art_leaf_t); fill_leaf(pop, D_RW(newleaf)->u.al, key, key_len, value, val_len); return newleaf; } static int longest_common_prefix(TOID(art_leaf) l1, TOID(art_leaf) l2, int depth) { TOID(var_string) l1_key = D_RO(l1)->key; TOID(var_string) l2_key = D_RO(l2)->key; int max_cmp; int idx; max_cmp = min(D_RO(l1_key)->len, D_RO(l2_key)->len) - depth; for (idx = 0; idx < max_cmp; idx++) { if (D_RO(l1_key)->s[depth + idx] != D_RO(l2_key)->s[depth + idx]) return idx; } return idx; } static void copy_header(art_node *dest, art_node *src) { dest->num_children = src->num_children; dest->partial_len = src->partial_len; memcpy(dest->partial, src->partial, min(MAX_PREFIX_LEN, src->partial_len)); } static void add_child256(PMEMobjpool *pop, TOID(art_node256) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child) { art_node *n_an; (void) ref; TX_ADD(n); n_an = &(D_RW(n)->n); n_an->num_children++; D_RW(n)->children[c] = child; } static void add_child48(PMEMobjpool *pop, TOID(art_node48) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child) { art_node *n_an; n_an = &(D_RW(n)->n); if (n_an->num_children < 48) { int pos = 0; TX_ADD(n); while (!(TOID_IS_NULL(D_RO(n)->children[pos]))) pos++; D_RW(n)->children[pos] = child; D_RW(n)->keys[c] = pos + 1; n_an->num_children++; } else { TOID(art_node_u) newnode_u = alloc_node(pop, NODE256); TOID(art_node256) newnode = D_RO(newnode_u)->u.an256; pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); for (int i = 0; i < 256; i++) { if (D_RO(n)->keys[i]) { D_RW(newnode)->children[i] = D_RO(n)->children[D_RO(n)->keys[i] - 1]; } } copy_header(&(D_RW(newnode)->n), n_an); *ref = newnode_u; TX_FREE(n); add_child256(pop, newnode, ref, c, child); } } static void add_child16(PMEMobjpool *pop, TOID(art_node16) n, TOID(art_node_u)*ref, unsigned char c, TOID(art_node_u) child) { art_node *n_an; n_an = &(D_RW(n)->n); if (n_an->num_children < 16) { __m128i cmp; TX_ADD(n); // Compare the key to all 16 stored keys cmp = _mm_cmplt_epi8(_mm_set1_epi8(c), _mm_loadu_si128((__m128i *)(D_RO(n)->keys))); // Use a mask to ignore children that don't exist unsigned mask = (1 << n_an->num_children) - 1; unsigned bitfield = _mm_movemask_epi8(cmp) & mask; // Check if less than any unsigned idx; if (bitfield) { idx = __builtin_ctz(bitfield); memmove(&(D_RW(n)->keys[idx + 1]), &(D_RO(n)->keys[idx]), n_an->num_children - idx); PMEMOIDmove(&(D_RW(n)->children[idx + 1].oid), &(D_RW(n)->children[idx].oid), n_an->num_children - idx); } else { idx = n_an->num_children; } // Set the child D_RW(n)->keys[idx] = c; D_RW(n)->children[idx] = child; n_an->num_children++; } else { TOID(art_node_u) newnode_u = alloc_node(pop, NODE48); TOID(art_node48) newnode = D_RO(newnode_u)->u.an48; // Copy the child pointers and populate the key map PMEMOIDcopy(&(D_RW(newnode)->children[0].oid), &(D_RO(n)->children[0].oid), n_an->num_children); for (int i = 0; i < n_an->num_children; i++) { D_RW(newnode)->keys[D_RO(n)->keys[i]] = i + 1; } copy_header(&(D_RW(newnode))->n, n_an); *ref = newnode_u; TX_FREE(n); add_child48(pop, newnode, ref, c, child); } } static void add_child4(PMEMobjpool *pop, TOID(art_node4) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child) { art_node *n_an; n_an = &(D_RW(n)->n); if (n_an->num_children < 4) { int idx; TX_ADD(n); for (idx = 0; idx < n_an->num_children; idx++) { if (c < D_RO(n)->keys[idx]) break; } // Shift to make room memmove(D_RW(n)->keys + idx + 1, D_RO(n)->keys + idx, n_an->num_children - idx); assert((idx + 1) < 4); PMEMOIDmove(&(D_RW(n)->children[idx + 1].oid), &(D_RW(n)->children[idx].oid), n_an->num_children - idx); // Insert element D_RW(n)->keys[idx] = c; D_RW(n)->children[idx] = child; n_an->num_children++; } else { TOID(art_node_u) newnode_u = alloc_node(pop, NODE16); TOID(art_node16) newnode = D_RO(newnode_u)->u.an16; pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); // Copy the child pointers and the key map PMEMOIDcopy(&(D_RW(newnode)->children[0].oid), &(D_RO(n)->children[0].oid), n_an->num_children); memcpy(D_RW(newnode)->keys, D_RO(n)->keys, n_an->num_children); copy_header(&(D_RW(newnode)->n), n_an); *ref = newnode_u; TX_FREE(n); add_child16(pop, newnode, ref, c, child); } } static void add_child(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) child) { switch (D_RO(n)->art_node_type) { case NODE4: add_child4(pop, D_RO(n)->u.an4, ref, c, child); break; case NODE16: add_child16(pop, D_RO(n)->u.an16, ref, c, child); break; case NODE48: add_child48(pop, D_RO(n)->u.an48, ref, c, child); break; case NODE256: add_child256(pop, D_RO(n)->u.an256, ref, c, child); break; default: abort(); } } static int prefix_mismatch(TOID(art_node_u) n, unsigned char *key, int key_len, int depth) { const art_node *n_an; int max_cmp; int idx; switch (D_RO(n)->art_node_type) { case NODE4: n_an = &(D_RO(D_RO(n)->u.an4)->n); break; case NODE16: n_an = &(D_RO(D_RO(n)->u.an16)->n); break; case NODE48: n_an = &(D_RO(D_RO(n)->u.an48)->n); break; case NODE256: n_an = &(D_RO(D_RO(n)->u.an256)->n); break; default: return 0; } max_cmp = min(min(MAX_PREFIX_LEN, n_an->partial_len), key_len - depth); for (idx = 0; idx < max_cmp; idx++) { if (n_an->partial[idx] != key[depth + idx]) return idx; } // If the prefix is short we can avoid finding a leaf if (n_an->partial_len > MAX_PREFIX_LEN) { // Prefix is longer than what we've checked, find a leaf TOID(art_leaf) l = minimum(n); max_cmp = min(D_RO(D_RO(l)->key)->len, key_len) - depth; for (; idx < max_cmp; idx++) { if (D_RO(D_RO(l)->key)->s[idx + depth] != key[depth + idx]) return idx; } } return idx; } static TOID(var_string) recursive_insert(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, const unsigned char *key, int key_len, void *value, int val_len, int depth, int *old) { art_node *n_an; TOID(var_string) retval; // If we are at a NULL node, inject a leaf if (TOID_IS_NULL(n)) { *ref = make_leaf(pop, key, key_len, value, val_len); TX_ADD(*ref); SET_LEAF(D_RW(*ref)); retval = null_var_string; return retval; } // If we are at a leaf, we need to replace it with a node if (IS_LEAF(D_RO(n))) { TOID(art_leaf)l = D_RO(n)->u.al; // Check if we are updating an existing value if (!leaf_matches(l, key, key_len, depth)) { *old = 1; retval = D_RO(l)->value; TX_ADD(D_RW(l)->value); COPY_BLOB(D_RW(l)->value, value, val_len); return retval; } // New value, we must split the leaf into a node4 pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); TOID(art_node_u) newnode_u = alloc_node(pop, NODE4); TOID(art_node4) newnode = D_RO(newnode_u)->u.an4; art_node *newnode_n = &(D_RW(newnode)->n); // Create a new leaf TOID(art_node_u) l2_u = make_leaf(pop, key, key_len, value, val_len); TOID(art_leaf) l2 = D_RO(l2_u)->u.al; // Determine longest prefix int longest_prefix = longest_common_prefix(l, l2, depth); newnode_n->partial_len = longest_prefix; memcpy(newnode_n->partial, key + depth, min(MAX_PREFIX_LEN, longest_prefix)); // Add the leafs to the newnode node4 *ref = newnode_u; add_child4(pop, newnode, ref, D_RO(D_RO(l)->key)->s[depth + longest_prefix], n); add_child4(pop, newnode, ref, D_RO(D_RO(l2)->key)->s[depth + longest_prefix], l2_u); return null_var_string; } // Check if given node has a prefix switch (D_RO(n)->art_node_type) { case NODE4: n_an = &(D_RW(D_RW(n)->u.an4)->n); break; case NODE16: n_an = &(D_RW(D_RW(n)->u.an16)->n); break; case NODE48: n_an = &(D_RW(D_RW(n)->u.an48)->n); break; case NODE256: n_an = &(D_RW(D_RW(n)->u.an256)->n); break; default: abort(); } if (n_an->partial_len) { // Determine if the prefixes differ, since we need to split int prefix_diff = prefix_mismatch(n, (unsigned char *)key, key_len, depth); if ((uint32_t)prefix_diff >= n_an->partial_len) { depth += n_an->partial_len; goto RECURSE_SEARCH; } // Create a new node pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); pmemobj_tx_add_range_direct(n_an, sizeof(art_node)); TOID(art_node_u) newnode_u = alloc_node(pop, NODE4); TOID(art_node4) newnode = D_RO(newnode_u)->u.an4; art_node *newnode_n = &(D_RW(newnode)->n); *ref = newnode_u; newnode_n->partial_len = prefix_diff; memcpy(newnode_n->partial, n_an->partial, min(MAX_PREFIX_LEN, prefix_diff)); // Adjust the prefix of the old node if (n_an->partial_len <= MAX_PREFIX_LEN) { add_child4(pop, newnode, ref, n_an->partial[prefix_diff], n); n_an->partial_len -= (prefix_diff + 1); memmove(n_an->partial, n_an->partial + prefix_diff + 1, min(MAX_PREFIX_LEN, n_an->partial_len)); } else { unsigned char *dst; const unsigned char *src; size_t len; n_an->partial_len -= (prefix_diff + 1); TOID(art_leaf) l = minimum(n); add_child4(pop, newnode, ref, D_RO(D_RO(l)->key)->s[depth + prefix_diff], n); dst = n_an->partial; src = &(D_RO(D_RO(l)->key)->s[depth + prefix_diff + 1 ]); len = min(MAX_PREFIX_LEN, n_an->partial_len); memcpy(dst, src, len); } // Insert the new leaf TOID(art_node_u) l = make_leaf(pop, key, key_len, value, val_len); SET_LEAF(D_RW(l)); add_child4(pop, newnode, ref, key[depth + prefix_diff], l); return null_var_string; } RECURSE_SEARCH:; // Find a child to recurse to TOID(art_node_u) *child = find_child(n, key[depth]); if (!TOID_IS_NULL(*child)) { return recursive_insert(pop, *child, child, key, key_len, value, val_len, depth + 1, old); } // No child, node goes within us TOID(art_node_u) l = make_leaf(pop, key, key_len, value, val_len); SET_LEAF(D_RW(l)); add_child(pop, n, ref, key[depth], l); retval = null_var_string; return retval; } /* * Returns the size of the ART tree */ uint64_t art_size(PMEMobjpool *pop) { TOID(struct art_tree_root) root; root = POBJ_ROOT(pop, struct art_tree_root); return D_RO(root)->size; } /* * Inserts a new value into the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @arg value Opaque value. * @return NULL if the item was newly inserted, otherwise * the old value pointer is returned. */ TOID(var_string) art_insert(PMEMobjpool *pop, const unsigned char *key, int key_len, void *value, int val_len) { int old_val = 0; TOID(var_string) old; TOID(struct art_tree_root) root; TX_BEGIN(pop) { root = POBJ_ROOT(pop, struct art_tree_root); TX_ADD(root); old = recursive_insert(pop, D_RO(root)->root, &(D_RW(root)->root), (const unsigned char *)key, key_len, value, val_len, 0, &old_val); if (!old_val) D_RW(root)->size++; } TX_ONABORT { abort(); } TX_END return old; } static void remove_child256(PMEMobjpool *pop, TOID(art_node256) n, TOID(art_node_u) *ref, unsigned char c) { art_node *n_an = &(D_RW(n)->n); TX_ADD(n); D_RW(n)->children[c].oid = OID_NULL; n_an->num_children--; // Resize to a node48 on underflow, not immediately to prevent // trashing if we sit on the 48/49 boundary if (n_an->num_children == 37) { TOID(art_node_u) newnode_u = alloc_node(pop, NODE48); TOID(art_node48) newnode_an48 = D_RO(newnode_u)->u.an48; pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); *ref = newnode_u; copy_header(&(D_RW(newnode_an48)->n), n_an); int pos = 0; for (int i = 0; i < 256; i++) { if (!TOID_IS_NULL(D_RO(n)->children[i])) { assert(pos < 48); D_RW(newnode_an48)->children[pos] = D_RO(n)->children[i]; D_RW(newnode_an48)->keys[i] = pos + 1; pos++; } } TX_FREE(n); } } static void remove_child48(PMEMobjpool *pop, TOID(art_node48) n, TOID(art_node_u) *ref, unsigned char c) { int pos = D_RO(n)->keys[c]; art_node *n_an = &(D_RW(n)->n); TX_ADD(n); D_RW(n)->keys[c] = 0; D_RW(n)->children[pos - 1].oid = OID_NULL; n_an->num_children--; if (n_an->num_children == 12) { TOID(art_node_u) newnode_u = alloc_node(pop, NODE16); TOID(art_node16) newnode_an16 = D_RO(newnode_u)->u.an16; pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); *ref = newnode_u; copy_header(&(D_RW(newnode_an16)->n), n_an); int child = 0; for (int i = 0; i < 256; i++) { pos = D_RO(n)->keys[i]; if (pos) { assert(child < 16); D_RW(newnode_an16)->keys[child] = i; D_RW(newnode_an16)->children[child] = D_RO(n)->children[pos - 1]; child++; } } TX_FREE(n); } } static void remove_child16(PMEMobjpool *pop, TOID(art_node16) n, TOID(art_node_u) *ref, TOID(art_node_u) *l) { int pos = l - &(D_RO(n)->children[0]); uint8_t num_children = ((D_RW(n)->n).num_children); TX_ADD(n); memmove(D_RW(n)->keys + pos, D_RO(n)->keys + pos + 1, num_children - 1 - pos); memmove(D_RW(n)->children + pos, D_RO(n)->children + pos + 1, (num_children - 1 - pos) * sizeof(void *)); ((D_RW(n)->n).num_children)--; if (--num_children == 3) { TOID(art_node_u) newnode_u = alloc_node(pop, NODE4); TOID(art_node4) newnode_an4 = D_RO(newnode_u)->u.an4; pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); *ref = newnode_u; copy_header(&(D_RW(newnode_an4)->n), &(D_RW(n)->n)); memcpy(D_RW(newnode_an4)->keys, D_RO(n)->keys, 4); memcpy(D_RW(newnode_an4)->children, D_RO(n)->children, 4 * sizeof(TOID(art_node_u))); TX_FREE(n); } } static void remove_child4(PMEMobjpool *pop, TOID(art_node4) n, TOID(art_node_u) *ref, TOID(art_node_u) *l) { int pos = l - &(D_RO(n)->children[0]); uint8_t *num_children = &((D_RW(n)->n).num_children); TX_ADD(n); memmove(D_RW(n)->keys + pos, D_RO(n)->keys + pos + 1, *num_children - 1 - pos); memmove(D_RW(n)->children + pos, D_RO(n)->children + pos + 1, (*num_children - 1 - pos) * sizeof(void *)); (*num_children)--; // Remove nodes with only a single child if (*num_children == 1) { TOID(art_node_u) child_u = D_RO(n)->children[0]; art_node *child = &(D_RW(D_RW(child_u)->u.an4)->n); pmemobj_tx_add_range_direct(ref, sizeof(TOID(art_node_u))); if (!IS_LEAF(D_RO(child_u))) { // Concatenate the prefixes int prefix = (D_RW(n)->n).partial_len; if (prefix < MAX_PREFIX_LEN) { (D_RW(n)->n).partial[prefix] = D_RO(n)->keys[0]; prefix++; } if (prefix < MAX_PREFIX_LEN) { int sub_prefix = min(child->partial_len, MAX_PREFIX_LEN - prefix); memcpy((D_RW(n)->n).partial + prefix, child->partial, sub_prefix); prefix += sub_prefix; } // Store the prefix in the child memcpy(child->partial, (D_RO(n)->n).partial, min(prefix, MAX_PREFIX_LEN)); child->partial_len += (D_RO(n)->n).partial_len + 1; } *ref = child_u; TX_FREE(n); } } static void remove_child(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, unsigned char c, TOID(art_node_u) *l) { switch (D_RO(n)->art_node_type) { case NODE4: return remove_child4(pop, D_RO(n)->u.an4, ref, l); case NODE16: return remove_child16(pop, D_RO(n)->u.an16, ref, l); case NODE48: return remove_child48(pop, D_RO(n)->u.an48, ref, c); case NODE256: return remove_child256(pop, D_RO(n)->u.an256, ref, c); default: abort(); } } static TOID(art_leaf) recursive_delete(PMEMobjpool *pop, TOID(art_node_u) n, TOID(art_node_u) *ref, const unsigned char *key, int key_len, int depth) { const art_node *n_an; // Search terminated if (TOID_IS_NULL(n)) return null_art_leaf; // Handle hitting a leaf node if (IS_LEAF(D_RO(n))) { TOID(art_leaf) l = D_RO(n)->u.al; if (!leaf_matches(l, key, key_len, depth)) { *ref = null_art_node_u; return l; } return null_art_leaf; } // get art_node component switch (D_RO(n)->art_node_type) { case NODE4: n_an = &(D_RO(D_RO(n)->u.an4)->n); break; case NODE16: n_an = &(D_RO(D_RO(n)->u.an16)->n); break; case NODE48: n_an = &(D_RO(D_RO(n)->u.an48)->n); break; case NODE256: n_an = &(D_RO(D_RO(n)->u.an256)->n); break; default: abort(); } // Bail if the prefix does not match if (n_an->partial_len) { int prefix_len = check_prefix(n_an, key, key_len, depth); if (prefix_len != min(MAX_PREFIX_LEN, n_an->partial_len)) { return null_art_leaf; } depth = depth + n_an->partial_len; } // Find child node TOID(art_node_u) *child = find_child(n, key[depth]); if (TOID_IS_NULL(*child)) return null_art_leaf; // If the child is leaf, delete from this node if (IS_LEAF(D_RO(*child))) { TOID(art_leaf)l = D_RO(*child)->u.al; if (!leaf_matches(l, key, key_len, depth)) { remove_child(pop, n, ref, key[depth], child); return l; } return null_art_leaf; } else { // Recurse return recursive_delete(pop, *child, child, (const unsigned char *)key, key_len, depth + 1); } } /* * Deletes a value from the ART tree * @arg t The tree * @arg key The key * @arg key_len The length of the key * @return NULL if the item was not found, otherwise * the value pointer is returned. */ TOID(var_string) art_delete(PMEMobjpool *pop, const unsigned char *key, int key_len) { TOID(struct art_tree_root)root = POBJ_ROOT(pop, struct art_tree_root); TOID(art_leaf) l; TOID(var_string) retval; retval = null_var_string; TX_BEGIN(pop) { TX_ADD(root); l = recursive_delete(pop, D_RO(root)->root, &D_RW(root)->root, key, key_len, 0); if (!TOID_IS_NULL(l)) { D_RW(root)->size--; TOID(var_string)old = D_RO(l)->value; TX_FREE(l); retval = old; } } TX_ONABORT { abort(); } TX_END return retval; } // Recursively iterates over the tree static int recursive_iter(TOID(art_node_u)n, art_callback cb, void *data) { const art_node *n_an; TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; TOID(art_leaf) l; TOID(var_string) key; TOID(var_string) value; cb_data cbd; // Handle base cases if (TOID_IS_NULL(n)) { return 0; } cbd.node = n; cbd.child_idx = -1; if (IS_LEAF(D_RO(n))) { l = D_RO(n)->u.al; key = D_RO(l)->key; value = D_RO(l)->value; return cb(&cbd, D_RO(key)->s, D_RO(key)->len, D_RO(value)->s, D_RO(value)->len); } int idx, res; switch (D_RO(n)->art_node_type) { case NODE4: an4 = D_RO(n)->u.an4; n_an = &(D_RO(an4)->n); for (int i = 0; i < n_an->num_children; i++) { cbd.child_idx = i; cb(&cbd, NULL, 0, NULL, 0); res = recursive_iter(D_RO(an4)->children[i], cb, data); if (res) return res; } break; case NODE16: an16 = D_RO(n)->u.an16; n_an = &(D_RO(an16)->n); for (int i = 0; i < n_an->num_children; i++) { cbd.child_idx = i; cb(&cbd, NULL, 0, NULL, 0); res = recursive_iter(D_RO(an16)->children[i], cb, data); if (res) return res; } break; case NODE48: an48 = D_RO(n)->u.an48; for (int i = 0; i < 256; i++) { idx = D_RO(an48)->keys[i]; if (!idx) continue; cbd.child_idx = idx - 1; cb(&cbd, NULL, 0, NULL, 0); res = recursive_iter(D_RO(an48)->children[idx - 1], cb, data); if (res) return res; } break; case NODE256: an256 = D_RO(n)->u.an256; for (int i = 0; i < 256; i++) { if (TOID_IS_NULL(D_RO(an256)->children[i])) continue; cbd.child_idx = i; cb(&cbd, NULL, 0, NULL, 0); res = recursive_iter(D_RO(an256)->children[i], cb, data); if (res) return res; } break; default: abort(); } return 0; } /* * Iterates through the entries pairs in the map, * invoking a callback for each. The call back gets a * key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter(PMEMobjpool *pop, art_callback cb, void *data) { TOID(struct art_tree_root) t = POBJ_ROOT(pop, struct art_tree_root); return recursive_iter(D_RO(t)->root, cb, data); } #ifdef LIBART_ITER_PREFIX /* { */ /* * Checks if a leaf prefix matches * @return 0 on success. */ static int leaf_prefix_matches(TOID(art_leaf) n, const unsigned char *prefix, int prefix_len) { // Fail if the key length is too short if (D_RO(D_RO(n)->key)->len < (uint32_t)prefix_len) return 1; // Compare the keys return memcmp(D_RO(D_RO(n)->key)->s, prefix, prefix_len); } /* * Iterates through the entries pairs in the map, * invoking a callback for each that matches a given prefix. * The call back gets a key, value for each and returns an integer stop value. * If the callback returns non-zero, then the iteration stops. * @arg t The tree to iterate over * @arg prefix The prefix of keys to read * @arg prefix_len The length of the prefix * @arg cb The callback function to invoke * @arg data Opaque handle passed to the callback * @return 0 on success, or the return of the callback. */ int art_iter_prefix(art_tree *t, const unsigned char *key, int key_len, art_callback cb, void *data) { art_node **child; art_node *n = t->root; int prefix_len, depth = 0; while (n) { // Might be a leaf if (IS_LEAF(n)) { n = LEAF_RAW(n); // Check if the expanded path matches if (!leaf_prefix_matches((art_leaf *)n, key, key_len)) { art_leaf *l = (art_leaf *)n; return cb(data, (const unsigned char *)l->key, l->key_len, l->value); } return 0; } // If the depth matches the prefix, we need to handle this node if (depth == key_len) { art_leaf *l = minimum(n); if (!leaf_prefix_matches(l, key, key_len)) return recursive_iter(n, cb, data); return 0; } // Bail if the prefix does not match if (n->partial_len) { prefix_len = prefix_mismatch(n, key, key_len, depth); // If there is no match, search is terminated if (!prefix_len) return 0; // If we've matched the prefix, iterate on this node else if (depth + prefix_len == key_len) { return recursive_iter(n, cb, data); } // if there is a full match, go deeper depth = depth + n->partial_len; } // Recursively search child = find_child(n, key[depth]); n = (child) ? *child : NULL; depth++; } return 0; } #endif /* } LIBART_ITER_PREFIX */ int fill_leaf(PMEMobjpool *pop, TOID(art_leaf) al, const unsigned char *key, int key_len, void *value, int val_len) { int retval = 0; size_t l_key; size_t l_val; TOID(var_string) Tkey; TOID(var_string) Tval; l_key = (sizeof(var_string) + key_len); l_val = (sizeof(var_string) + val_len); Tkey = TX_ALLOC(var_string, l_key); Tval = TX_ALLOC(var_string, l_val); COPY_BLOB(Tkey, key, key_len); COPY_BLOB(Tval, value, val_len); D_RW(al)->key = Tkey; D_RW(al)->value = Tval; return retval; } pmdk-1.4.1/src/examples/libpmemobj/libart/art.h000066400000000000000000000134301331545616200214200ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2012, Armon Dadgar. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: art.h * * Description: header file for art tree on pmem implementation * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ /* * based on https://github.com/armon/libart/src/art.h */ #ifndef _ART_H #define _ART_H #ifdef __cplusplus extern "C" { #endif #define MAX_PREFIX_LEN 10 typedef enum { NODE4 = 0, NODE16 = 1, NODE48 = 2, NODE256 = 3, art_leaf_t = 4, art_node_types = 5 /* number of different art_nodes */ } art_node_type; char *art_node_names[] = { "art_node4", "art_node16", "art_node48", "art_node256", "art_leaf" }; /* * forward declarations; these are required when typedef shall be * used instead of struct */ struct _art_node_u; typedef struct _art_node_u art_node_u; struct _art_node; typedef struct _art_node art_node; struct _art_node4; typedef struct _art_node4 art_node4; struct _art_node16; typedef struct _art_node16 art_node16; struct _art_node48; typedef struct _art_node48 art_node48; struct _art_node256; typedef struct _art_node256 art_node256; struct _art_leaf; typedef struct _art_leaf art_leaf; struct _var_string; typedef struct _var_string var_string; POBJ_LAYOUT_BEGIN(arttree_tx); POBJ_LAYOUT_ROOT(arttree_tx, struct art_tree_root); POBJ_LAYOUT_TOID(arttree_tx, art_node_u); POBJ_LAYOUT_TOID(arttree_tx, art_node4); POBJ_LAYOUT_TOID(arttree_tx, art_node16); POBJ_LAYOUT_TOID(arttree_tx, art_node48); POBJ_LAYOUT_TOID(arttree_tx, art_node256); POBJ_LAYOUT_TOID(arttree_tx, art_leaf); POBJ_LAYOUT_TOID(arttree_tx, var_string); POBJ_LAYOUT_END(arttree_tx); struct _var_string { size_t len; unsigned char s[]; }; /* * This struct is included as part of all the various node sizes */ struct _art_node { uint8_t num_children; uint32_t partial_len; unsigned char partial[MAX_PREFIX_LEN]; }; /* * Small node with only 4 children */ struct _art_node4 { art_node n; unsigned char keys[4]; TOID(art_node_u) children[4]; }; /* * Node with 16 children */ struct _art_node16 { art_node n; unsigned char keys[16]; TOID(art_node_u) children[16]; }; /* * Node with 48 children, but a full 256 byte field. */ struct _art_node48 { art_node n; unsigned char keys[256]; TOID(art_node_u) children[48]; }; /* * Full node with 256 children */ struct _art_node256 { art_node n; TOID(art_node_u) children[256]; }; /* * Represents a leaf. These are of arbitrary size, as they include the key. */ struct _art_leaf { TOID(var_string) value; TOID(var_string) key; }; struct _art_node_u { uint8_t art_node_type; uint8_t art_node_tag; union { TOID(art_node4) an4; /* starts with art_node */ TOID(art_node16) an16; /* starts with art_node */ TOID(art_node48) an48; /* starts with art_node */ TOID(art_node256) an256; /* starts with art_node */ TOID(art_leaf) al; } u; }; struct art_tree_root { int size; TOID(art_node_u) root; }; typedef struct _cb_data { TOID(art_node_u) node; int child_idx; } cb_data; /* * Macros to manipulate art_node tags */ #define IS_LEAF(x) ((x->art_node_type == art_leaf_t)) #define SET_LEAF(x) ((x->art_node_tag = art_leaf_t)) #define COPY_BLOB(_obj, _blob, _len) \ D_RW(_obj)->len = _len; \ TX_MEMCPY(D_RW(_obj)->s, _blob, _len); \ D_RW(_obj)->s[_len - 1] = '\0'; typedef int(*art_callback)(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *value, uint32_t val_len); extern int art_tree_init(PMEMobjpool *pop, int *newpool); extern uint64_t art_size(PMEMobjpool *pop); extern int art_iter(PMEMobjpool *pop, art_callback cb, void *data); extern TOID(var_string) art_insert(PMEMobjpool *pop, const unsigned char *key, int key_len, void *value, int val_len); extern TOID(var_string) art_search(PMEMobjpool *pop, const unsigned char *key, int key_len); extern TOID(var_string) art_delete(PMEMobjpool *pop, const unsigned char *key, int key_len); #ifdef __cplusplus } #endif #endif /* _ART_H */ pmdk-1.4.1/src/examples/libpmemobj/libart/arttree.c000066400000000000000000000376701331545616200223070ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree.c * * Description: implement ART tree using libpmemobj based on libart * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #include #include #include #include #include #ifdef __FreeBSD__ #define _WITH_GETLINE #endif #include #include #include #include #include #include #include #include #include #include "libpmemobj.h" #include "arttree.h" /* * dummy structure so far; this should correspond to the datastore * structure as defined in examples/libpmemobj/tree_map/datastore */ struct datastore { void *priv; }; /* * context - main context of datastore */ struct ds_context { char *filename; /* name of pool file */ int mode; /* operation mode */ int insertions; /* number of insert operations to perform */ int newpool; /* complete new memory pool */ size_t psize; /* size of pool */ PMEMobjpool *pop; /* pmemobj handle */ bool fileio; unsigned fmode; int fd; /* file descriptor for file io mode */ char *addr; /* base mapping address for file io mode */ unsigned char *key; /* for SEARCH, INSERT and REMOVE */ uint32_t key_len; unsigned char *value; /* for INSERT */ uint32_t val_len; }; #define FILL (1 << 1) #define DUMP (1 << 2) #define GRAPH (1 << 3) #define INSERT (1 << 4) #define SEARCH (1 << 5) #define REMOVE (1 << 6) struct ds_context my_context; extern TOID(var_string) null_var_string; extern TOID(art_leaf) null_art_leaf; extern TOID(art_node_u) null_art_node_u; #define read_key(p) read_line(p) #define read_value(p) read_line(p) int initialize_context(struct ds_context *ctx, int ac, char *av[]); int initialize_pool(struct ds_context *ctx); int add_elements(struct ds_context *ctx); int insert_element(struct ds_context *ctx); int search_element(struct ds_context *ctx); int delete_element(struct ds_context *ctx); ssize_t read_line(unsigned char **line); void exit_handler(struct ds_context *ctx); int art_tree_map_init(struct datastore *ds, struct ds_context *ctx); void pmemobj_ds_set_priv(struct datastore *ds, void *priv); static int dump_art_leaf_callback(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len); static int dump_art_node_callback(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len); static void print_node_info(char *nodetype, uint64_t off, const art_node *an); static int parse_keyval(struct ds_context *ctx, char *arg, int mode); int initialize_context(struct ds_context *ctx, int ac, char *av[]) { int errors = 0; int opt; char mode; if ((ctx == NULL) || (ac < 2)) { errors++; } if (!errors) { ctx->filename = NULL; ctx->psize = PMEMOBJ_MIN_POOL; ctx->newpool = 0; ctx->pop = NULL; ctx->fileio = false; ctx->fmode = 0666; ctx->mode = 0; ctx->fd = -1; } if (!errors) { while ((opt = getopt(ac, av, "s:m:n:")) != -1) { switch (opt) { case 'm': mode = optarg[0]; if (mode == 'f') { ctx->mode |= FILL; } else if (mode == 'd') { ctx->mode |= DUMP; } else if (mode == 'g') { ctx->mode |= GRAPH; } else if (mode == 'i') { ctx->mode |= INSERT; parse_keyval(ctx, av[optind], INSERT); optind++; } else if (mode == 's') { ctx->mode |= SEARCH; parse_keyval(ctx, av[optind], SEARCH); optind++; } else if (mode == 'r') { ctx->mode |= REMOVE; parse_keyval(ctx, av[optind], REMOVE); optind++; } else { errors++; } break; case 'n': { long insertions; insertions = strtol(optarg, NULL, 0); if (insertions > 0 && insertions < LONG_MAX) { ctx->insertions = insertions; } break; } case 's': { long poolsize; poolsize = strtol(optarg, NULL, 0); if (poolsize >= PMEMOBJ_MIN_POOL) { ctx->psize = poolsize; } break; } default: errors++; break; } } } if (!errors) { ctx->filename = strdup(av[optind]); } return errors; } static int parse_keyval(struct ds_context *ctx, char *arg, int mode) { int errors = 0; char *p; p = strtok(arg, ":"); if (p == NULL) { errors++; } if (!errors) { if (ctx->mode & (SEARCH|REMOVE|INSERT)) { ctx->key = (unsigned char *)strdup(p); assert(ctx->key != NULL); ctx->key_len = strlen(p) + 1; } if (ctx->mode & INSERT) { p = strtok(NULL, ":"); assert(p != NULL); ctx->value = (unsigned char *)strdup(p); assert(ctx->value != NULL); ctx->val_len = strlen(p) + 1; } } return errors; } void exit_handler(struct ds_context *ctx) { if (!ctx->fileio) { if (ctx->pop) { pmemobj_close(ctx->pop); } } else { if (ctx->fd > (-1)) { close(ctx->fd); } } } int art_tree_map_init(struct datastore *ds, struct ds_context *ctx) { int errors = 0; char *error_string; /* calculate a required pool size */ if (ctx->psize < PMEMOBJ_MIN_POOL) ctx->psize = PMEMOBJ_MIN_POOL; if (!ctx->fileio) { if (access(ctx->filename, F_OK) != 0) { error_string = "pmemobj_create"; ctx->pop = pmemobj_create(ctx->filename, POBJ_LAYOUT_NAME(arttree_tx), ctx->psize, ctx->fmode); ctx->newpool = 1; } else { error_string = "pmemobj_open"; ctx->pop = pmemobj_open(ctx->filename, POBJ_LAYOUT_NAME(arttree_tx)); } if (ctx->pop == NULL) { perror(error_string); errors++; } } else { int flags = O_CREAT | O_RDWR | O_SYNC; /* Create a file if it does not exist. */ if ((ctx->fd = open(ctx->filename, flags, ctx->fmode)) < 0) { perror(ctx->filename); errors++; } /* allocate the pmem */ if ((errno = posix_fallocate(ctx->fd, 0, ctx->psize)) != 0) { perror("posix_fallocate"); errors++; } /* map file to memory */ if ((ctx->addr = mmap(NULL, ctx->psize, PROT_READ, MAP_SHARED, ctx->fd, 0)) == MAP_FAILED) { perror("mmap"); errors++; } } if (!errors) { pmemobj_ds_set_priv(ds, ctx); } else { if (ctx->fileio) { if (ctx->addr != NULL) { munmap(ctx->addr, ctx->psize); } if (ctx->fd >= 0) { close(ctx->fd); } } else { if (ctx->pop) { pmemobj_close(ctx->pop); } } } return errors; } /* * pmemobj_ds_set_priv -- set private structure of datastore */ void pmemobj_ds_set_priv(struct datastore *ds, void *priv) { ds->priv = priv; } struct datastore myds; static void usage(char *progname) { printf("usage: %s -m [f|d|g] file\n", progname); printf(" -m mode known modes are\n"); printf(" f fill create and fill art tree\n"); printf(" i insert insert an element into the art tree\n"); printf(" s search search for a key in the art tree\n"); printf(" r remove remove an element from the art tree\n"); printf(" d dump dump art tree\n"); printf(" g graph dump art tree as a graphviz dot graph\n"); printf(" -n number of key-value pairs to insert" " into the art tree\n"); printf(" -s size in bytes of the memory pool" " (minimum and default: 8 MB)"); printf("\nfilling an art tree is done by reading key-value pairs\n" "from standard input.\n" "Both keys and values are single line only.\n"); } int main(int argc, char *argv[]) { if (initialize_context(&my_context, argc, argv) != 0) { usage(argv[0]); return 1; } if (art_tree_map_init(&myds, &my_context) != 0) { fprintf(stderr, "failed to initialize memory pool file\n"); return 1; } if (my_context.pop == NULL) { perror("pool initialization"); return 1; } if (art_tree_init(my_context.pop, &my_context.newpool)) { perror("pool setup"); return 1; } if ((my_context.mode & FILL)) { if (add_elements(&my_context)) { perror("add elements"); return 1; } } if ((my_context.mode & INSERT)) { if (insert_element(&my_context)) { perror("insert elements"); return 1; } } if ((my_context.mode & SEARCH)) { if (search_element(&my_context)) { perror("search elements"); return 1; } } if ((my_context.mode & REMOVE)) { if (delete_element(&my_context)) { perror("delete elements"); return 1; } } if (my_context.mode & DUMP) { art_iter(my_context.pop, dump_art_leaf_callback, NULL); } if (my_context.mode & GRAPH) { printf("digraph g {\nrankdir=LR;\n"); art_iter(my_context.pop, dump_art_node_callback, NULL); printf("}"); } exit_handler(&my_context); return 0; } int add_elements(struct ds_context *ctx) { PMEMobjpool *pop; int errors = 0; int i; int key_len; int val_len; unsigned char *key; unsigned char *value; if (ctx == NULL) { errors++; } else if (ctx->pop == NULL) { errors++; } if (!errors) { pop = ctx->pop; for (i = 0; i < ctx->insertions; i++) { key = NULL; value = NULL; key_len = read_key(&key); val_len = read_value(&value); art_insert(pop, key, key_len, value, val_len); if (key != NULL) free(key); if (value != NULL) free(value); } } return errors; } int insert_element(struct ds_context *ctx) { PMEMobjpool *pop; int errors = 0; if (ctx == NULL) { errors++; } else if (ctx->pop == NULL) { errors++; } if (!errors) { pop = ctx->pop; art_insert(pop, ctx->key, ctx->key_len, ctx->value, ctx->val_len); } return errors; } int search_element(struct ds_context *ctx) { PMEMobjpool *pop; TOID(var_string) value; int errors = 0; if (ctx == NULL) { errors++; } else if (ctx->pop == NULL) { errors++; } if (!errors) { pop = ctx->pop; printf("search key [%s]: ", (char *)ctx->key); value = art_search(pop, ctx->key, ctx->key_len); if (TOID_IS_NULL(value)) { printf("not found\n"); } else { printf("value [%s]\n", D_RO(value)->s); } } return errors; } int delete_element(struct ds_context *ctx) { PMEMobjpool *pop; int errors = 0; if (ctx == NULL) { errors++; } else if (ctx->pop == NULL) { errors++; } if (!errors) { pop = ctx->pop; art_delete(pop, ctx->key, ctx->key_len); } return errors; } ssize_t read_line(unsigned char **line) { size_t len = -1; ssize_t read = -1; *line = NULL; if ((read = getline((char **)line, &len, stdin)) > 0) { (*line)[read - 1] = '\0'; } return read; } static int dump_art_leaf_callback(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len) { cb_data *cbd; if (data != NULL) { cbd = (cb_data *)data; printf("node type %d ", D_RO(cbd->node)->art_node_type); if (D_RO(cbd->node)->art_node_type == art_leaf_t) { printf("key len %d = [%s], value len %d = [%s]", key_len, key != NULL ? (char *)key : (char *)"NULL", val_len, val != NULL ? (char *)val : (char *)"NULL"); } printf("\n"); } else { printf("key len %d = [%s], value len %d = [%s]\n", key_len, key != NULL ? (char *)key : (char *)"NULL", val_len, val != NULL ? (char *)val : (char *)"NULL"); } return 0; } static void print_node_info(char *nodetype, uint64_t off, const art_node *an) { int p_len, i; p_len = an->partial_len; printf("N%" PRIx64 " [label=\"%s at\\n0x%" PRIx64 "\\n%d children", off, nodetype, off, an->num_children); if (p_len != 0) { printf("\\nlen %d", p_len); printf(": "); for (i = 0; i < p_len; i++) { printf("%c", an->partial[i]); } } printf("\"];\n"); } static int dump_art_node_callback(void *data, const unsigned char *key, uint32_t key_len, const unsigned char *val, uint32_t val_len) { cb_data *cbd; const art_node *an; TOID(art_node4) an4; TOID(art_node16) an16; TOID(art_node48) an48; TOID(art_node256) an256; TOID(art_leaf) al; TOID(art_node_u) child; TOID(var_string) oid_key; TOID(var_string) oid_value; if (data != NULL) { cbd = (cb_data *)data; switch (D_RO(cbd->node)->art_node_type) { case NODE4: an4 = D_RO(cbd->node)->u.an4; an = &(D_RO(an4)->n); child = D_RO(an4)->children[cbd->child_idx]; if (!TOID_IS_NULL(child)) { print_node_info("node4", cbd->node.oid.off, an); printf("N%" PRIx64 " -> N%" PRIx64 " [label=\"%c\"];\n", cbd->node.oid.off, child.oid.off, D_RO(an4)->keys[cbd->child_idx]); } break; case NODE16: an16 = D_RO(cbd->node)->u.an16; an = &(D_RO(an16)->n); child = D_RO(an16)->children[cbd->child_idx]; if (!TOID_IS_NULL(child)) { print_node_info("node16", cbd->node.oid.off, an); printf("N%" PRIx64 " -> N%" PRIx64 " [label=\"%c\"];\n", cbd->node.oid.off, child.oid.off, D_RO(an16)->keys[cbd->child_idx]); } break; case NODE48: an48 = D_RO(cbd->node)->u.an48; an = &(D_RO(an48)->n); child = D_RO(an48)->children[cbd->child_idx]; if (!TOID_IS_NULL(child)) { print_node_info("node48", cbd->node.oid.off, an); printf("N%" PRIx64 " -> N%" PRIx64 " [label=\"%c\"];\n", cbd->node.oid.off, child.oid.off, D_RO(an48)->keys[cbd->child_idx]); } break; case NODE256: an256 = D_RO(cbd->node)->u.an256; an = &(D_RO(an256)->n); child = D_RO(an256)->children[cbd->child_idx]; if (!TOID_IS_NULL(child)) { print_node_info("node256", cbd->node.oid.off, an); printf("N%" PRIx64 " -> N%" PRIx64 " [label=\"0x%x\"];\n", cbd->node.oid.off, child.oid.off, (char)((cbd->child_idx) & 0xff)); } break; case art_leaf_t: al = D_RO(cbd->node)->u.al; oid_key = D_RO(al)->key; oid_value = D_RO(al)->value; printf("N%" PRIx64 " [shape=box," "label=\"leaf at\\n0x%" PRIx64 "\"];\n", cbd->node.oid.off, cbd->node.oid.off); printf("N%" PRIx64 " [shape=box," "label=\"key at 0x%" PRIx64 ": %s\"];\n", oid_key.oid.off, oid_key.oid.off, D_RO(oid_key)->s); printf("N%" PRIx64 " [shape=box," "label=\"value at 0x%" PRIx64 ": %s\"];\n", oid_value.oid.off, oid_value.oid.off, D_RO(oid_value)->s); printf("N%" PRIx64 " -> N%" PRIx64 ";\n", cbd->node.oid.off, oid_key.oid.off); printf("N%" PRIx64 " -> N%" PRIx64 ";\n", cbd->node.oid.off, oid_value.oid.off); break; default: break; } } else { printf("leaf: key len %d = [%s], value len %d = [%s]\n", key_len, key, val_len, val); } return 0; } pmdk-1.4.1/src/examples/libpmemobj/libart/arttree.h000066400000000000000000000043201331545616200222760ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree.h * * Description: header file for art tree on pmem implementation * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #ifndef _ARTTREE_H #define _ARTTREE_H #ifdef __cplusplus extern "C" { #endif #include "art.h" #ifdef __cplusplus } #endif #endif /* _ARTTREE_H */ pmdk-1.4.1/src/examples/libpmemobj/libart/arttree_examine.c000066400000000000000000000302521331545616200240020ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree_examine.c * * Description: implementation of examine function for ART tree structures * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #include #include #include #include #include #include #include #include #include #include "arttree_structures.h" /* * examine context */ struct examine_ctx { struct pmem_context *pmem_ctx; char *offset_string; uint64_t offset; char *type_name; int32_t type; int32_t hexdump; }; static struct examine_ctx *ex_ctx = NULL; struct examine { const char *name; const char *brief; int (*func)(char *, struct examine_ctx *, off_t); void (*help)(char *); }; /* local functions */ static int examine_parse_args(char *appname, int ac, char *av[], struct examine_ctx *ex_ctx); static struct examine *get_examine(char *type_name); static void print_usage(char *appname); static void dump_PMEMoid(char *prefix, PMEMoid *oid); static int examine_PMEMoid(char *appname, struct examine_ctx *ctx, off_t off); static int examine_art_tree_root(char *appname, struct examine_ctx *ctx, off_t off); static int examine_art_node_u(char *appname, struct examine_ctx *ctx, off_t off); static int examine_art_node4(char *appname, struct examine_ctx *ctx, off_t off); static int examine_art_node16(char *appname, struct examine_ctx *ctx, off_t off); static int examine_art_node48(char *appname, struct examine_ctx *ctx, off_t off); static int examine_art_node256(char *appname, struct examine_ctx *ctx, off_t off); #if 0 /* XXX */ static int examine_art_node(char *appname, struct examine_ctx *ctx, off_t off); #else static int examine_art_node(art_node *an); #endif static int examine_art_leaf(char *appname, struct examine_ctx *ctx, off_t off); static int examine_var_string(char *appname, struct examine_ctx *ctx, off_t off); /* global visible interface */ void arttree_examine_help(char *appname); int arttree_examine_func(char *appname, struct pmem_context *ctx, int ac, char *av[]); static const char *arttree_examine_help_str = "Examine data structures (objects) of ART tree\n" "Arguments: \n" " offset of object in pmem file\n" " one of art_tree_root, art_node_u, art_node," " art_node4, art_node16, art_node48, art_node256, art_leaf\n" ; static const struct option long_options[] = { {"hexdump", no_argument, NULL, 'x'}, {NULL, 0, NULL, 0 }, }; static struct examine ex_funcs[] = { { .name = "PMEMobj", .brief = "examine PMEMoid structure", .func = examine_PMEMoid, .help = NULL, }, { .name = "art_tree_root", .brief = "examine art_tree_root structure", .func = examine_art_tree_root, .help = NULL, }, { .name = "art_node_u", .brief = "examine art_node_u structure", .func = examine_art_node_u, .help = NULL, }, { .name = "art_node4", .brief = "examine art_node4 structure", .func = examine_art_node4, .help = NULL, }, { .name = "art_node16", .brief = "examine art_node16 structure", .func = examine_art_node16, .help = NULL, }, { .name = "art_node48", .brief = "examine art_node48 structure", .func = examine_art_node48, .help = NULL, }, { .name = "art_node256", .brief = "examine art_node256 structure", .func = examine_art_node256, .help = NULL, }, { .name = "art_leaf", .brief = "examine art_leaf structure", .func = examine_art_leaf, .help = NULL, }, { .name = "var_string", .brief = "examine var_string structure", .func = examine_var_string, .help = NULL, }, }; /* * number of arttree examine commands */ #define COMMANDS_NUMBER (sizeof(ex_funcs) / sizeof(ex_funcs[0])) void arttree_examine_help(char *appname) { printf("%s %s\n", appname, arttree_examine_help_str); } int arttree_examine_func(char *appname, struct pmem_context *ctx, int ac, char *av[]) { int errors = 0; off_t offset; struct examine *ex; if (ctx == NULL) { return -1; } if (ex_ctx == NULL) { ex_ctx = (struct examine_ctx *) calloc(1, sizeof(struct examine_ctx)); if (ex_ctx == NULL) { return -1; } } ex_ctx->pmem_ctx = ctx; if (examine_parse_args(appname, ac, av, ex_ctx) != 0) { fprintf(stderr, "%s::%s: error parsing arguments\n", appname, __FUNCTION__); errors++; } if (!errors) { offset = (off_t)strtol(ex_ctx->offset_string, NULL, 0); ex = get_examine(ex_ctx->type_name); if (ex != NULL) { ex->func(appname, ex_ctx, offset); } } return errors; } static int examine_parse_args(char *appname, int ac, char *av[], struct examine_ctx *ex_ctx) { int ret = 0; int opt; optind = 0; while ((opt = getopt_long(ac, av, "x", long_options, NULL)) != -1) { switch (opt) { case 'x': ex_ctx->hexdump = 1; break; default: print_usage(appname); ret = 1; } } if (ret == 0) { ex_ctx->offset_string = strdup(av[optind + 0]); ex_ctx->type_name = strdup(av[optind + 1]); } return ret; } static void print_usage(char *appname) { printf("%s: examine \n", appname); } /* * get_command -- returns command for specified command name */ static struct examine * get_examine(char *type_name) { int i; if (type_name == NULL) { return NULL; } for (i = 0; i < COMMANDS_NUMBER; i++) { if (strcmp(type_name, ex_funcs[i].name) == 0) return &ex_funcs[i]; } return NULL; } static void dump_PMEMoid(char *prefix, PMEMoid *oid) { printf("%s { PMEMoid pool_uuid_lo %" PRIx64 " off 0x%" PRIx64 " = %" PRId64 " }\n", prefix, oid->pool_uuid_lo, oid->off, oid->off); } static int examine_PMEMoid(char *appname, struct examine_ctx *ctx, off_t off) { void *p = (void *)(ctx->pmem_ctx->addr + off); dump_PMEMoid("PMEMoid", p); return 0; } static int examine_art_tree_root(char *appname, struct examine_ctx *ctx, off_t off) { art_tree_root *tree_root = (art_tree_root *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_tree_root {\n", (long long)off); printf(" size %d\n", tree_root->size); dump_PMEMoid(" art_node_u", (PMEMoid *)&(tree_root->root)); printf("\n};\n"); return 0; } static int examine_art_node_u(char *appname, struct examine_ctx *ctx, off_t off) { art_node_u *node_u = (art_node_u *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_node_u {\n", (long long)off); printf(" type %d [%s]\n", node_u->art_node_type, art_node_names[node_u->art_node_type]); printf(" tag %d\n", node_u->art_node_tag); switch (node_u->art_node_type) { case ART_NODE4: dump_PMEMoid(" art_node4 oid", &(node_u->u.an4.oid)); break; case ART_NODE16: dump_PMEMoid(" art_node16 oid", &(node_u->u.an16.oid)); break; case ART_NODE48: dump_PMEMoid(" art_node48 oid", &(node_u->u.an48.oid)); break; case ART_NODE256: dump_PMEMoid(" art_node256 oid", &(node_u->u.an256.oid)); break; case ART_LEAF: dump_PMEMoid(" art_leaf oid", &(node_u->u.al.oid)); break; default: printf("ERROR: unknown node type\n"); break; } printf("\n};\n"); return 0; } static int examine_art_node4(char *appname, struct examine_ctx *ctx, off_t off) { art_node4 *an4 = (art_node4 *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_node4 {\n", (long long)off); examine_art_node(&(an4->n)); printf("keys ["); for (int i = 0; i < 4; i++) { printf("%c ", an4->keys[i]); } printf("]\nnodes [\n"); for (int i = 0; i < 4; i++) { dump_PMEMoid(" art_node_u oid", &(an4->children[i].oid)); } printf("\n]"); printf("\n};\n"); return 0; } static int examine_art_node16(char *appname, struct examine_ctx *ctx, off_t off) { art_node16 *an16 = (art_node16 *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_node16 {\n", (long long)off); examine_art_node(&(an16->n)); printf("keys ["); for (int i = 0; i < 16; i++) { printf("%c ", an16->keys[i]); } printf("]\nnodes [\n"); for (int i = 0; i < 16; i++) { dump_PMEMoid(" art_node_u oid", &(an16->children[i].oid)); } printf("\n]"); printf("\n};\n"); return 0; } static int examine_art_node48(char *appname, struct examine_ctx *ctx, off_t off) { art_node48 *an48 = (art_node48 *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_node48 {\n", (long long)off); examine_art_node(&(an48->n)); printf("keys ["); for (int i = 0; i < 256; i++) { printf("%c ", an48->keys[i]); } printf("]\nnodes [\n"); for (int i = 0; i < 48; i++) { dump_PMEMoid(" art_node_u oid", &(an48->children[i].oid)); } printf("\n]"); printf("\n};\n"); return 0; } static int examine_art_node256(char *appname, struct examine_ctx *ctx, off_t off) { art_node256 *an256 = (art_node256 *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_node256 {\n", (long long)off); examine_art_node(&(an256->n)); printf("nodes [\n"); for (int i = 0; i < 256; i++) { dump_PMEMoid(" art_node_u oid", &(an256->children[i].oid)); } printf("\n]"); printf("\n};\n"); return 0; } #if 0 /* XXX */ static int examine_art_node(char *appname, struct examine_ctx *ctx, off_t off) { art_node *an = (art_node *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_node {\n", (long long)off); printf(" num_children %d\n", an->num_children); printf(" partial_len %d\n", an->partial_len); printf(" partial ["); for (int i = 0; i < 10; i++) { printf("%c ", an->partial[i]); } printf("\n]"); printf("\n};\n"); return 0; } #else static int examine_art_node(art_node *an) { printf("art_node {\n"); printf(" num_children %d\n", an->num_children); printf(" partial_len %d\n", an->partial_len); printf(" partial ["); for (int i = 0; i < 10; i++) { printf("%c ", an->partial[i]); } printf("\n]"); printf("\n};\n"); return 0; } #endif static int examine_art_leaf(char *appname, struct examine_ctx *ctx, off_t off) { art_leaf *al = (art_leaf *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, art_leaf {\n", (long long)off); dump_PMEMoid(" var_string key oid ", &(al->key.oid)); dump_PMEMoid(" var_string value oid", &(al->value.oid)); printf("\n};\n"); return 0; } static int examine_var_string(char *appname, struct examine_ctx *ctx, off_t off) { var_string *vs = (var_string *)(ctx->pmem_ctx->addr + off); printf("at offset 0x%llx, var_string {\n", (long long)off); printf(" len %ld s [%s]", vs->len, vs->s); printf("\n};\n"); return 0; } pmdk-1.4.1/src/examples/libpmemobj/libart/arttree_search.c000066400000000000000000000257211331545616200236260ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree_search.c * * Description: implementation of search function for ART tree * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include "arttree_structures.h" /* * search context */ struct search_ctx { struct pmem_context *pmem_ctx; unsigned char *search_key; int32_t hexdump; }; static struct search_ctx *s_ctx = NULL; struct search { const char *name; const char *brief; char *(*func)(char *, struct search_ctx *); void (*help)(char *); }; /* local functions */ static int search_parse_args(char *appname, int ac, char *av[], struct search_ctx *s_ctx); static struct search *get_search(char *type_name); static void print_usage(char *appname); static void dump_PMEMoid(char *prefix, PMEMoid *oid); static char *search_key(char *appname, struct search_ctx *ctx); static int leaf_matches(struct search_ctx *ctx, art_leaf *n, unsigned char *key, int key_len, int depth); static int check_prefix(art_node *an, unsigned char *key, int key_len, int depth); static uint64_t find_child(art_node *n, int node_type, unsigned char key); static void *get_node(struct search_ctx *ctx, int node_type, uint64_t off); static uint64_t get_offset_an(art_node_u *au); static void dump_PMEMoid(char *prefix, PMEMoid *oid); static void dump_art_tree_root(char *prefix, uint64_t off, void *p); /* global visible interface */ void arttree_search_help(char *appname); int arttree_search_func(char *appname, struct pmem_context *ctx, int ac, char *av[]); static const char *arttree_search_help_str = "Search for key in ART tree\n" "Arguments: \n" " key\n" ; static const struct option long_options[] = { {"hexdump", no_argument, NULL, 'x'}, {NULL, 0, NULL, 0 }, }; static struct search s_funcs[] = { { .name = "key", .brief = "search for key", .func = search_key, .help = NULL, } }; /* Simple inlined function */ static inline int min(int a, int b) { return (a < b) ? b : a; } /* * number of arttree examine commands */ #define COMMANDS_NUMBER (sizeof(s_funcs) / sizeof(s_funcs[0])) void arttree_search_help(char *appname) { printf("%s %s\n", appname, arttree_search_help_str); } int arttree_search_func(char *appname, struct pmem_context *ctx, int ac, char *av[]) { int errors = 0; struct search *s; char *value; value = NULL; if (ctx == NULL) { return -1; } if (s_ctx == NULL) { s_ctx = (struct search_ctx *)malloc(sizeof(struct search_ctx)); if (s_ctx == NULL) { return -1; } memset(s_ctx, 0, sizeof(struct search_ctx)); } if (ctx->art_tree_root_offset == 0) { fprintf(stderr, "search functions require knowledge" " about the art_tree_root.\n"); fprintf(stderr, "Use \"set_root \"" " to define where the \nart_tree_root object" " resides in the pmem file.\n"); errors++; } s_ctx->pmem_ctx = ctx; if (search_parse_args(appname, ac, av, s_ctx) != 0) { fprintf(stderr, "%s::%s: error parsing arguments\n", appname, __FUNCTION__); errors++; } if (!errors) { s = get_search("key"); if (s != NULL) { value = s->func(appname, s_ctx); } if (value != NULL) { printf("key [%s] found, value [%s]\n", s_ctx->search_key, value); } else { printf("key [%s] not found\n", s_ctx->search_key); } } if (s_ctx->search_key != NULL) { free(s_ctx->search_key); } free(s_ctx); return errors; } static int search_parse_args(char *appname, int ac, char *av[], struct search_ctx *s_ctx) { int ret = 0; int opt; optind = 0; while ((opt = getopt_long(ac, av, "x", long_options, NULL)) != -1) { switch (opt) { case 'x': s_ctx->hexdump = 1; break; default: print_usage(appname); ret = 1; } } if (ret == 0) { s_ctx->search_key = (unsigned char *)strdup(av[optind + 0]); } return ret; } static void print_usage(char *appname) { printf("%s: search \n", appname); } /* * get_search -- returns command for specified command name */ static struct search * get_search(char *type_name) { int i; if (type_name == NULL) { return NULL; } for (i = 0; i < COMMANDS_NUMBER; i++) { if (strcmp(type_name, s_funcs[i].name) == 0) return &s_funcs[i]; } return NULL; } static void * get_node(struct search_ctx *ctx, int node_type, uint64_t off) { if (!VALID_NODE_TYPE(node_type)) return NULL; printf("%s at off 0x%" PRIx64 "\n", art_node_names[node_type], off); return ctx->pmem_ctx->addr + off; } static int leaf_matches(struct search_ctx *ctx, art_leaf *n, unsigned char *key, int key_len, int depth) { var_string *n_key; (void) depth; n_key = (var_string *)get_node(ctx, VAR_STRING, n->key.oid.off); if (n_key == NULL) return 1; // HACK for stupid null-terminated strings.... // else if (n_key->len != key_len) // ret = 1; if (n_key->len != key_len + 1) return 1; return memcmp(n_key->s, key, key_len); } static int check_prefix(art_node *n, unsigned char *key, int key_len, int depth) { int max_cmp = min(min(n->partial_len, MAX_PREFIX_LEN), key_len - depth); int idx; for (idx = 0; idx < max_cmp; idx++) { if (n->partial[idx] != key[depth + idx]) return idx; } return idx; } static uint64_t find_child(art_node *n, int node_type, unsigned char c) { int i; union { art_node4 *p1; art_node16 *p2; art_node48 *p3; art_node256 *p4; } p; printf("[%s] children %d search key %c [", art_node_names[node_type], n->num_children, c); switch (node_type) { case ART_NODE4: p.p1 = (art_node4 *)n; for (i = 0; i < n->num_children; i++) { printf("%c ", p.p1->keys[i]); if (p.p1->keys[i] == c) { printf("]\n"); return p.p1->children[i].oid.off; } } break; case ART_NODE16: p.p2 = (art_node16 *)n; for (i = 0; i < n->num_children; i++) { printf("%c ", p.p2->keys[i]); if (p.p2->keys[i] == c) { printf("]\n"); return p.p2->children[i].oid.off; } } break; case ART_NODE48: p.p3 = (art_node48 *)n; i = p.p3->keys[c]; printf("%d ", p.p3->keys[c]); if (i) { printf("]\n"); return p.p3->children[i - 1].oid.off; } break; case ART_NODE256: p.p4 = (art_node256 *)n; printf("0x%" PRIx64, p.p4->children[c].oid.off); if (p.p4->children[c].oid.off != 0) { printf("]\n"); return p.p4->children[c].oid.off; } break; default: abort(); } printf("]\n"); return 0; } static uint64_t get_offset_an(art_node_u *au) { uint64_t offset = 0; switch (au->art_node_type) { case ART_NODE4: offset = au->u.an4.oid.off; break; case ART_NODE16: offset = au->u.an16.oid.off; break; case ART_NODE48: offset = au->u.an48.oid.off; break; case ART_NODE256: offset = au->u.an256.oid.off; break; case ART_LEAF: offset = au->u.al.oid.off; break; default: break; } return offset; } static char * search_key(char *appname, struct search_ctx *ctx) { int errors = 0; void *p; /* something */ off_t p_off; art_node_u *p_au; /* art_node_u */ off_t p_au_off; void *p_an; /* specific art node from art_node_u */ off_t p_an_off; art_node *an; /* art node */ var_string *n_value; char *value; int prefix_len; int depth = 0; int key_len; uint64_t child_off; key_len = strlen((char *)(ctx->search_key)); value = NULL; p_off = ctx->pmem_ctx->art_tree_root_offset; p = get_node(ctx, ART_TREE_ROOT, p_off); assert(p != NULL); dump_art_tree_root("art_tree_root", p_off, p); p_au_off = ((art_tree_root *)p)->root.oid.off; p_au = (art_node_u *)get_node(ctx, ART_NODE_U, p_au_off); if (p_au == NULL) errors++; if (!errors) { while (p_au) { p_an_off = get_offset_an(p_au); p_an = get_node(ctx, p_au->art_node_type, p_an_off); assert(p_an != NULL); if (p_au->art_node_type == ART_LEAF) { if (!leaf_matches(ctx, (art_leaf *)p_an, ctx->search_key, key_len, depth)) { n_value = (var_string *) get_node(ctx, VAR_STRING, ((art_leaf *)p_an)->value.oid.off); return (char *)(n_value->s); } } an = (art_node *)p_an; if (an->partial_len) { prefix_len = check_prefix(an, ctx->search_key, key_len, depth); if (prefix_len != min(MAX_PREFIX_LEN, an->partial_len)) { return NULL; } depth = depth + an->partial_len; } child_off = find_child(an, p_au->art_node_type, ctx->search_key[depth]); if (child_off != 0) { p_au_off = child_off; p_au = get_node(ctx, ART_NODE_U, p_au_off); } else { p_au = NULL; } depth++; } } if (errors) { return NULL; } else { return value; } } static void dump_art_tree_root(char *prefix, uint64_t off, void *p) { art_tree_root *tree_root; tree_root = (art_tree_root *)p; printf("at offset 0x%" PRIx64 ", art_tree_root {\n", off); printf(" size %d\n", tree_root->size); dump_PMEMoid(" art_node_u", (PMEMoid *)&(tree_root->root)); printf("\n};\n"); } static void dump_PMEMoid(char *prefix, PMEMoid *oid) { printf("%s { PMEMoid pool_uuid_lo %" PRIx64 " off 0x%" PRIx64 " = %" PRId64 " }\n", prefix, oid->pool_uuid_lo, oid->off, oid->off); } pmdk-1.4.1/src/examples/libpmemobj/libart/arttree_structures.c000066400000000000000000000346071331545616200246070ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree_structures.c * * Description: Examine pmem structures; structures and unions taken from * the preprocessor output of a libpmemobj compatible program. * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #ifdef __FreeBSD__ #define _WITH_GETLINE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "arttree_structures.h" #include #define APPNAME "examine_arttree" #define SRCVERSION "0.2" size_t art_node_sizes[art_node_types] = { sizeof(art_node4), sizeof(art_node16), sizeof(art_node48), sizeof(art_node256), sizeof(art_leaf), sizeof(art_node_u), sizeof(art_node), sizeof(art_tree_root), sizeof(var_string), }; char *art_node_names[art_node_types] = { "art_node4", "art_node16", "art_node48", "art_node256", "art_leaf", "art_node_u", "art_node", "art_tree_root", "var_string" }; /* * long_options -- command line arguments */ static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0 }, }; /* * command -- struct for commands definition */ struct command { const char *name; const char *brief; int (*func)(char *, struct pmem_context *, int, char *[]); void (*help)(char *); }; /* * number of arttree_structures commands */ #define COMMANDS_NUMBER (sizeof(commands) / sizeof(commands[0])) static void print_help(char *appname); static void print_usage(char *appname); static void print_version(char *appname); static int quit_func(char *appname, struct pmem_context *ctx, int argc, char *argv[]); static void quit_help(char *appname); static int set_root_func(char *appname, struct pmem_context *ctx, int argc, char *argv[]); static void set_root_help(char *appname); static int help_func(char *appname, struct pmem_context *ctx, int argc, char *argv[]); static void help_help(char *appname); static struct command *get_command(char *cmd_str); static int ctx_init(struct pmem_context *ctx, char *filename); static int arttree_structures_func(char *appname, struct pmem_context *ctx, int ac, char *av[]); static void arttree_structures_help(char *appname); static int arttree_info_func(char *appname, struct pmem_context *ctx, int ac, char *av[]); static void arttree_info_help(char *appname); extern int arttree_examine_func(); extern void arttree_examine_help(); extern int arttree_search_func(); extern void arttree_search_help(); void outv_err(const char *fmt, ...); void outv_err_vargs(const char *fmt, va_list ap); static struct command commands[] = { { .name = "structures", .brief = "print information about ART structures", .func = arttree_structures_func, .help = arttree_structures_help, }, { .name = "info", .brief = "print information and statistics" " about an ART tree pool", .func = arttree_info_func, .help = arttree_info_help, }, { .name = "examine", .brief = "examine data structures from an ART tree", .func = arttree_examine_func, .help = arttree_examine_help, }, { .name = "search", .brief = "search for a key in an ART tree", .func = arttree_search_func, .help = arttree_search_help, }, { .name = "set_root", .brief = "define offset of root of an ART tree", .func = set_root_func, .help = set_root_help, }, { .name = "help", .brief = "print help text about a command", .func = help_func, .help = help_help, }, { .name = "quit", .brief = "quit ART tree structure examiner", .func = quit_func, .help = quit_help, }, }; static struct pmem_context ctx; /* * outv_err -- print error message */ void outv_err(const char *fmt, ...) { va_list ap; va_start(ap, fmt); outv_err_vargs(fmt, ap); va_end(ap); } /* * outv_err_vargs -- print error message */ void outv_err_vargs(const char *fmt, va_list ap) { fprintf(stderr, "error: "); vfprintf(stderr, fmt, ap); if (!strchr(fmt, '\n')) fprintf(stderr, "\n"); } /* * print_usage -- prints usage message */ static void print_usage(char *appname) { printf("usage: %s [--help] []\n", appname); } /* * print_version -- prints version message */ static void print_version(char *appname) { printf("%s %s\n", appname, SRCVERSION); } /* * print_help -- prints help message */ static void print_help(char *appname) { print_usage(appname); print_version(appname); printf("\n"); printf("Options:\n"); printf(" -h, --help display this help and exit\n"); printf("\n"); printf("The available commands are:\n"); int i; for (i = 0; i < COMMANDS_NUMBER; i++) printf("%s\t- %s\n", commands[i].name, commands[i].brief); printf("\n"); } /* * set_root_help -- prints help message for set root command */ static void set_root_help(char *appname) { printf("Usage: set_root \n"); printf(" define the offset of the art tree root\n"); } /* * set_root_func -- set_root define the offset of the art tree root */ static int set_root_func(char *appname, struct pmem_context *ctx, int argc, char *argv[]) { int retval = 0; uint64_t root_offset; if (argc == 2) { root_offset = strtol(argv[1], NULL, 0); ctx->art_tree_root_offset = root_offset; } else { set_root_help(appname); retval = 1; } return retval; } /* * quit_help -- prints help message for quit command */ static void quit_help(char *appname) { printf("Usage: quit\n"); printf(" terminate arttree structure examiner\n"); } /* * quit_func -- quit arttree structure examiner */ static int quit_func(char *appname, struct pmem_context *ctx, int argc, char *argv[]) { printf("\n"); exit(0); return 0; } /* * help_help -- prints help message for help command */ static void help_help(char *appname) { printf("Usage: %s help \n", appname); } /* * help_func -- prints help message for specified command */ static int help_func(char *appname, struct pmem_context *ctx, int argc, char *argv[]) { if (argc > 1) { char *cmd_str = argv[1]; struct command *cmdp = get_command(cmd_str); if (cmdp && cmdp->help) { cmdp->help(appname); return 0; } else { outv_err("No help text for '%s' command\n", cmd_str); return -1; } } else { print_help(appname); return -1; } } static const char *arttree_structures_help_str = "Show information about known ART tree structures\n" ; static void arttree_structures_help(char *appname) { printf("%s %s\n", appname, arttree_structures_help_str); } static int arttree_structures_func(char *appname, struct pmem_context *ctx, int ac, char *av[]) { (void) appname; (void) ac; (void) av; printf( "typedef struct pmemoid {\n" " uint64_t pool_uuid_lo;\n" " uint64_t off;\n" "} PMEMoid;\n"); printf("sizeof(PMEMoid) = %ld\n\n\n", sizeof(PMEMoid)); printf( "struct _art_node_u; typedef struct _art_node_u art_node_u;\n" "struct _art_node_u { \n" " uint8_t art_node_type; \n" " uint8_t art_node_tag; \n" "};\n"); printf("sizeof(art_node_u) = %ld\n\n\n", sizeof(art_node_u)); printf( "struct _art_node; typedef struct _art_node art_node;\n" "struct _art_node {\n" " uint8_t type;\n" " uint8_t num_children;\n" " uint32_t partial_len;\n" " unsigned char partial[10];\n" "};\n"); printf("sizeof(art_node) = %ld\n\n\n", sizeof(art_node)); printf( "typedef uint8_t _toid_art_node_toid_type_num[8];\n"); printf("sizeof(_toid_art_node_toid_type_num[8]) = %ld\n\n\n", sizeof(_toid_art_node_toid_type_num[8])); printf( "union _toid_art_node_u_toid {\n" " PMEMoid oid;\n" " art_node_u *_type;\n" " _toid_art_node_u_toid_type_num *_type_num;\n" "};\n"); printf("sizeof(union _toid_art_node_u_toid) = %ld\n\n\n", sizeof(union _toid_art_node_u_toid)); printf( "typedef uint8_t _toid_art_node_toid_type_num[8];\n"); printf("sizeof(_toid_art_node_toid_type_num[8]) = %ld\n\n\n", sizeof(_toid_art_node_toid_type_num[8])); printf( "union _toid_art_node_toid {\n" " PMEMoid oid; \n" " art_node *_type; \n" " _toid_art_node_toid_type_num *_type_num;\n" "};\n"); printf("sizeof(union _toid_art_node_toid) = %ld\n\n\n", sizeof(union _toid_art_node_toid)); printf( "struct _art_node4; typedef struct _art_node4 art_node4;\n" "struct _art_node4 {\n" " art_node n;\n" " unsigned char keys[4];\n" " union _toid_art_node_u_toid children[4];\n" "};\n"); printf("sizeof(art_node4) = %ld\n\n\n", sizeof(art_node4)); printf( "struct _art_node16; typedef struct _art_node16 art_node16;\n" "struct _art_node16 {\n" " art_node n;\n" " unsigned char keys[16];\n" " union _toid_art_node_u_toid children[16];\n" "};\n"); printf("sizeof(art_node16) = %ld\n\n\n", sizeof(art_node16)); printf( "struct _art_node48; typedef struct _art_node48 art_node48;\n" "struct _art_node48 {\n" " art_node n;\n" " unsigned char keys[256];\n" " union _toid_art_node_u_toid children[48];\n" "};\n"); printf("sizeof(art_node48) = %ld\n\n\n", sizeof(art_node48)); printf( "struct _art_node256; typedef struct _art_node256 art_node256;\n" "struct _art_node256 {\n" " art_ndoe n;\n" " union _toid_art_node_u_toid children[256];\n" "};\n"); printf("sizeof(art_node256) = %ld\n\n\n", sizeof(art_node256)); printf( "struct _art_leaf; typedef struct _art_leaf art_leaf;\n" "struct _art_leaf {\n" " union _toid_var_string_toid value;\n" " union _toid_var_string_toid key;\n" "};\n"); printf("sizeof(art_leaf) = %ld\n\n\n", sizeof(art_leaf)); return 0; } static const char *arttree_info_help_str = "Show information about known ART tree structures\n" ; static void arttree_info_help(char *appname) { printf("%s %s\n", appname, arttree_info_help_str); } static int arttree_info_func(char *appname, struct pmem_context *ctx, int ac, char *av[]) { printf("%s: %s not yet implemented\n", appname, __FUNCTION__); return 0; } /* * get_command -- returns command for specified command name */ static struct command * get_command(char *cmd_str) { int i; if (cmd_str == NULL) { return NULL; } for (i = 0; i < COMMANDS_NUMBER; i++) { if (strcmp(cmd_str, commands[i].name) == 0) return &commands[i]; } return NULL; } static int ctx_init(struct pmem_context *ctx, char *filename) { int errors = 0; if (filename == NULL) errors++; if (ctx == NULL) errors++; if (errors) return errors; ctx->filename = strdup(filename); assert(ctx->filename != NULL); ctx->fd = -1; ctx->addr = NULL; ctx->art_tree_root_offset = 0; if (access(ctx->filename, F_OK) != 0) return 1; if ((ctx->fd = open(ctx->filename, O_RDONLY)) == -1) return 1; struct stat stbuf; if (fstat(ctx->fd, &stbuf) < 0) return 1; ctx->psize = stbuf.st_size; if ((ctx->addr = mmap(NULL, ctx->psize, PROT_READ, MAP_SHARED, ctx->fd, 0)) == MAP_FAILED) return 1; return 0; } static void ctx_fini(struct pmem_context *ctx) { munmap(ctx->addr, ctx->psize); close(ctx->fd); free(ctx->filename); } int main(int ac, char *av[]) { int opt; int option_index; int ret = 0; size_t len; ssize_t read; char *cmd_str; char *args[20]; int nargs; char *line; struct command *cmdp = NULL; while ((opt = getopt_long(ac, av, "h", long_options, &option_index)) != -1) { switch (opt) { case 'h': print_help(APPNAME); return 0; default: print_usage(APPNAME); return -1; } } if (optind >= ac) { fprintf(stderr, "ERROR: missing arguments\n"); print_usage(APPNAME); return -1; } ctx_init(&ctx, av[optind]); if (optind + 1 < ac) { /* execute command as given on command line */ cmd_str = av[optind + 1]; cmdp = get_command(cmd_str); if (cmdp != NULL) { ret = cmdp->func(APPNAME, &ctx, ac - 2, av + 2); } } else { /* interactive mode: read commands and execute them */ line = NULL; printf("\n> "); while ((read = getline(&line, &len, stdin)) != -1) { if (line[read - 1] == '\n') { line[read - 1] = '\0'; } args[0] = strtok(line, " "); cmdp = get_command(args[0]); if (cmdp == NULL) { printf("[%s]: command not supported\n", args[0] ? args[0] : "NULL"); printf("\n> "); continue; } nargs = 1; while (1) { args[nargs] = strtok(NULL, " "); if (args[nargs] == NULL) { break; } nargs++; } ret = cmdp->func(APPNAME, &ctx, nargs, args); printf("\n> "); } if (line != NULL) { free(line); } } ctx_fini(&ctx); return ret; } pmdk-1.4.1/src/examples/libpmemobj/libart/arttree_structures.h000066400000000000000000000133671331545616200246140ustar00rootroot00000000000000/* * Copyright 2016, FUJITSU TECHNOLOGY SOLUTIONS GMBH * Copyright 2016-2017, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * Filename: arttree_structures.h * * Description: known structures of the ART tree * * Author: Andreas Bluemle, Dieter Kasper * Andreas.Bluemle.external@ts.fujitsu.com * dieter.kasper@ts.fujitsu.com * * Organization: FUJITSU TECHNOLOGY SOLUTIONS GMBH * * =========================================================================== */ #ifndef _ARTTREE_STRUCTURES_H #define _ARTTREE_STRUCTURES_H #define MAX_PREFIX_LEN 10 /* * pmem_context -- structure for pmempool file */ struct pmem_context { char *filename; size_t psize; int fd; char *addr; uint64_t art_tree_root_offset; }; struct _art_node_u; typedef struct _art_node_u art_node_u; struct _art_node; typedef struct _art_node art_node; struct _art_node4; typedef struct _art_node4 art_node4; struct _art_node16; typedef struct _art_node16 art_node16; struct _art_node48; typedef struct _art_node48 art_node48; struct _art_node256; typedef struct _art_node256 art_node256; struct _var_string; typedef struct _var_string var_string; struct _art_leaf; typedef struct _art_leaf art_leaf; struct _art_tree_root; typedef struct _art_tree_root art_tree_root; typedef uint8_t art_tree_root_toid_type_num[65535]; typedef uint8_t _toid_art_node_u_toid_type_num[2]; typedef uint8_t _toid_art_node_toid_type_num[3]; typedef uint8_t _toid_art_node4_toid_type_num[4]; typedef uint8_t _toid_art_node16_toid_type_num[5]; typedef uint8_t _toid_art_node48_toid_type_num[6]; typedef uint8_t _toid_art_node256_toid_type_num[7]; typedef uint8_t _toid_art_leaf_toid_type_num[8]; typedef uint8_t _toid_var_string_toid_type_num[9]; typedef struct pmemoid { uint64_t pool_uuid_lo; uint64_t off; } PMEMoid; union _toid_art_node_u_toid { PMEMoid oid; art_node_u *_type; _toid_art_node_u_toid_type_num *_type_num; }; union art_tree_root_toid { PMEMoid oid; struct art_tree_root *_type; art_tree_root_toid_type_num *_type_num; }; union _toid_art_node_toid { PMEMoid oid; art_node *_type; _toid_art_node_toid_type_num *_type_num; }; union _toid_art_node4_toid { PMEMoid oid; art_node4 *_type; _toid_art_node4_toid_type_num *_type_num; }; union _toid_art_node16_toid { PMEMoid oid; art_node16 *_type; _toid_art_node16_toid_type_num *_type_num; }; union _toid_art_node48_toid { PMEMoid oid; art_node48 *_type; _toid_art_node48_toid_type_num *_type_num; }; union _toid_art_node256_toid { PMEMoid oid; art_node256 *_type; _toid_art_node256_toid_type_num *_type_num; }; union _toid_var_string_toid { PMEMoid oid; var_string *_type; _toid_var_string_toid_type_num *_type_num; }; union _toid_art_leaf_toid { PMEMoid oid; art_leaf *_type; _toid_art_leaf_toid_type_num *_type_num; }; struct _art_tree_root { int size; union _toid_art_node_u_toid root; }; struct _art_node { uint8_t num_children; uint32_t partial_len; unsigned char partial[MAX_PREFIX_LEN]; }; struct _art_node4 { art_node n; unsigned char keys[4]; union _toid_art_node_u_toid children[4]; }; struct _art_node16 { art_node n; unsigned char keys[16]; union _toid_art_node_u_toid children[16]; }; struct _art_node48 { art_node n; unsigned char keys[256]; union _toid_art_node_u_toid children[48]; }; struct _art_node256 { art_node n; union _toid_art_node_u_toid children[256]; }; struct _var_string { size_t len; unsigned char s[]; }; struct _art_leaf { union _toid_var_string_toid value; union _toid_var_string_toid key; }; struct _art_node_u { uint8_t art_node_type; uint8_t art_node_tag; union { union _toid_art_node4_toid an4; union _toid_art_node16_toid an16; union _toid_art_node48_toid an48; union _toid_art_node256_toid an256; union _toid_art_leaf_toid al; } u; }; typedef enum { ART_NODE4 = 0, ART_NODE16 = 1, ART_NODE48 = 2, ART_NODE256 = 3, ART_LEAF = 4, ART_NODE_U = 5, ART_NODE = 6, ART_TREE_ROOT = 7, VAR_STRING = 8, art_node_types = 9 /* number of different art_nodes */ } art_node_type; #define VALID_NODE_TYPE(n) (((n) >= 0) && ((n) < art_node_types)) extern size_t art_node_sizes[]; extern char *art_node_names[]; #endif /* _ARTTREE_STRUCTURES_H */ pmdk-1.4.1/src/examples/libpmemobj/linkedlist/000077500000000000000000000000001331545616200213455ustar00rootroot00000000000000pmdk-1.4.1/src/examples/libpmemobj/linkedlist/.gitignore000066400000000000000000000000051331545616200233300ustar00rootroot00000000000000fifo pmdk-1.4.1/src/examples/libpmemobj/linkedlist/Makefile000066400000000000000000000033321331545616200230060ustar00rootroot00000000000000# # Copyright 2016, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # examples/libpmemobj/linkedlist/Makefile -- build the tail queue examples # PROGS = fifo LIBS = -lpmemobj -lpmem -pthread include ../../Makefile.inc fifo: fifo.o fifo.o: pmemobj_list.h pmdk-1.4.1/src/examples/libpmemobj/linkedlist/README000066400000000000000000000010061331545616200222220ustar00rootroot00000000000000Persistent Memory Development Kit This is examples/libpmemobj/linkedlist/README. This directory contains an implementation of singly linked list and tail queue in pmem_list.h. fifo.c contains an usage example of persistent tail queue. Syntax of example usage is given below. fifo