├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── include ├── process_handle.hpp └── process_handle │ ├── linux_storage.hpp │ ├── osx_storage.hpp │ └── windows_storage.hpp └── test ├── CMakeLists.txt └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | /.vs 34 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/Catch"] 2 | path = test/Catch 3 | url = https://github.com/philsquared/Catch 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: trusty 4 | 5 | matrix: 6 | include: 7 | 8 | # Linux C++14 GCC builds 9 | - os: linux 10 | compiler: gcc 11 | addons: &gcc6 12 | apt: 13 | sources: ['ubuntu-toolchain-r-test'] 14 | packages: ['g++-6'] 15 | env: COMPILER='g++-6' BUILD_TYPE='Release' 16 | 17 | - os: linux 18 | compiler: gcc 19 | addons: *gcc6 20 | env: COMPILER='g++-6' BUILD_TYPE='Debug' 21 | 22 | # Linux C++14 Clang builds 23 | - os: linux 24 | compiler: clang 25 | addons: &clang40 26 | apt: 27 | sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test'] 28 | packages: ['clang-4.0', libc++-dev, libc++abi-dev] 29 | env: COMPILER='clang++-4.0' BUILD_TYPE='Release' 30 | 31 | - os: linux 32 | compiler: clang 33 | addons: *clang40 34 | env: COMPILER='clang++-4.0' BUILD_TYPE='Debug' 35 | 36 | # OSX C++14 Clang Builds 37 | 38 | - os: osx 39 | osx_image: xcode8.3 40 | compiler: clang 41 | env: COMPILER='clang++' BUILD_TYPE='Debug' 42 | 43 | - os: osx 44 | osx_image: xcode8.3 45 | compiler: clang 46 | env: COMPILER='clang++' BUILD_TYPE='Release' 47 | 48 | 49 | install: 50 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 51 | - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} 52 | - | 53 | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then 54 | CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz" 55 | mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 56 | export PATH=${DEPS_DIR}/cmake/bin:${PATH} 57 | elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then 58 | which cmake || brew install cmake 59 | fi 60 | before_script: 61 | - export CXX=${COMPILER} 62 | - cd ${TRAVIS_BUILD_DIR} 63 | - cmake -H. -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -Wdev 64 | - cd Build 65 | 66 | script: 67 | - make -j 2 68 | - sudo ctest -V -j 2 69 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(process_handle) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") 7 | 8 | include_directories (${PROJECT_SOURCE_DIR}/include) 9 | add_library (process_handle INTERFACE) 10 | target_include_directories (process_handle INTERFACE ${PROJECT_SOURCE_DIR}/include) 11 | target_sources (process_handle INTERFACE ${PROJECT_SOURCE_DIR}/include/process_handle.hpp) 12 | 13 | enable_testing() 14 | add_subdirectory (test) 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # process_handle [![Build Status](https://travis-ci.org/JustasMasiulis/process_handle.svg?branch=master)](https://travis-ci.org/JustasMasiulis/process_handle) [![Build status](https://ci.appveyor.com/api/projects/status/3osunqdm82hkg3is?svg=true)](https://ci.appveyor.com/project/JustasMasiulis/process-handle) 2 | A cross platform wrapper around system native handles that allows copying and RAII based leak freedom. 3 | 4 | ## installation 5 | the library is headers only so copying it into your project directory and including it is enough. 6 | 7 | ## quick reference 8 | Default constructed process_handle is a handle to our own process. 9 | It is also possible to construct process_handle using a process id 10 | or an already existing handle. 11 | ```c++ 12 | #include "process_handle.hpp" 13 | 14 | jm::process_handle h; 15 | h.owner_id(); // will be our own process id 16 | auto native_handle = h.native(); // returns the OS specific native handle 17 | if(h) { // conversion operator to bool 18 | h.reset(); // invalidates the handle stored in h 19 | h.reset(native_handle); // or replaces it with a new one 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # version string format -- This will be overwritten later anyway 2 | version: "{build}" 3 | 4 | os: 5 | - Visual Studio 2017 6 | - Visual Studio 2015 7 | 8 | init: 9 | - git config --global core.autocrlf input 10 | # Set build version to git commit-hash 11 | - ps: Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_BRANCH) - $($env:APPVEYOR_REPO_COMMIT)" 12 | 13 | install: 14 | - git submodule update --init --recursive 15 | 16 | # Win32 and x64 are CMake-compatible solution platform names. 17 | # This allows us to pass %PLATFORM% to CMake -A. 18 | platform: 19 | - Win32 20 | - x64 21 | 22 | # build Configurations, i.e. Debug, Release, etc. 23 | configuration: 24 | - Debug 25 | - Release 26 | 27 | #Cmake will autodetect the compiler, but we set the arch 28 | before_build: 29 | - cmake -H. -BBuild -A%PLATFORM% 30 | 31 | # build with MSBuild 32 | build: 33 | project: Build\process_handle.sln # path to Visual Studio solution or project 34 | parallel: true # enable MSBuild parallel builds 35 | verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed} 36 | 37 | test_script: 38 | - cd Build 39 | - ctest -V -j 2 -C %CONFIGURATION% -------------------------------------------------------------------------------- /include/process_handle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef JM_PROCESS_HANDLE_HPP 18 | #define JM_PROCESS_HANDLE_HPP 19 | 20 | #if defined(_WIN32) 21 | #include "process_handle/windows_storage.hpp" 22 | #elif defined(__linux__) 23 | #include "process_handle/linux_storage.hpp" 24 | #elif defined(__APPLE__) 25 | #include "process_handle/osx_storage.hpp" 26 | #else 27 | #error unknown operating system 28 | #endif // defined(_WIN32) 29 | 30 | namespace jm { 31 | 32 | using pid_t = detail::pid_t; 33 | using native_handle_t = detail::native_handle_t; 34 | 35 | class process_handle { 36 | detail::handle_storage _storage; 37 | 38 | public: 39 | /// \brief Default constructed process_handle is treated as our own process. 40 | explicit process_handle() noexcept(noexcept(detail::handle_storage())) 41 | : _storage() {} // MSVC has internal error if I simply = default it 42 | 43 | /// \brief Destroys the handle. 44 | /// \note On windows handle is reference counted and may not be closed upon destruction. 45 | ~process_handle() noexcept = default; 46 | 47 | /// \brief Opens a handle to process of given id. 48 | explicit process_handle(pid_t process_id) noexcept(noexcept(detail::handle_storage(process_id))) 49 | : _storage(process_id) {} 50 | 51 | /// \brief Opens a handle to process of given id, sets an error code on failure. 52 | explicit process_handle(pid_t process_id, std::error_code& ec) noexcept(noexcept(detail::handle_storage( 53 | process_id, ec))) 54 | : _storage(process_id, ec) {} 55 | 56 | #ifndef __linux__ // on linux handle == pid 57 | 58 | /// \brief Adopts an existing handle. 59 | explicit process_handle(native_handle_t handle) noexcept(noexcept(detail::handle_storage(handle))) 60 | : _storage(handle) {} 61 | 62 | #endif 63 | 64 | /// \brief Copy constructible. 65 | process_handle(const process_handle& other) noexcept = default; 66 | /// \brief Copy assignable. 67 | process_handle& operator=(const process_handle& other) noexcept = default; 68 | 69 | /// \brief Move constructible. 70 | process_handle(process_handle&& other) noexcept = default; 71 | /// \brief Move assignable. 72 | process_handle& operator=(process_handle&& other) noexcept = default; 73 | 74 | /// \brief Returns the native platform specific handle. 75 | native_handle_t native() const noexcept { return _storage.native(); } 76 | 77 | /// \brief Invalidates handle stored in current object. 78 | /// \note On windows handles are reference counted and may not be closed upon call to this function. 79 | void reset(std::nullptr_t p = nullptr) noexcept { _storage.reset(); } 80 | 81 | /// \brief Sets the stored handle to given handle and then closes the old handle. 82 | /// \param native_handle The new handle to replace old one with. 83 | /// \note On windows handles are reference counted and may not be closed upon call to this function. 84 | void reset(native_handle_t native_handle) noexcept { _storage.reset(native_handle); } 85 | 86 | /// \brief The id of process that we have the handle to. 87 | pid_t owner_id() const noexcept(noexcept(_storage.pid())) { return _storage.pid(); } 88 | 89 | /// \brief The id of process that we have the handle to. 90 | pid_t owner_id(std::error_code& ec) const noexcept { return _storage.pid(ec); } 91 | 92 | /// \brief Check whether the handle is valid. 93 | explicit operator bool() const noexcept { return _storage.valid(); } 94 | }; // process_handle 95 | 96 | } // namespace jm 97 | 98 | #endif // include guard 99 | -------------------------------------------------------------------------------- /include/process_handle/linux_storage.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef JM_PROCESS_HANDLE_STORAGE_LINUX_HPP 18 | #define JM_PROCESS_HANDLE_STORAGE_LINUX_HPP 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace jm { namespace detail { 25 | 26 | using pid_t = ::pid_t; 27 | using native_handle_t = pid_t; 28 | 29 | class handle_storage { 30 | native_handle_t _handle; 31 | 32 | public: 33 | explicit handle_storage() noexcept 34 | : _handle(::getpid()) {} 35 | 36 | explicit handle_storage(native_handle_t handle, std::error_code&) noexcept 37 | : _handle(handle) {} 38 | 39 | explicit handle_storage(native_handle_t handle) noexcept 40 | : _handle(handle) {} 41 | 42 | handle_storage(const handle_storage& other) noexcept = default; 43 | handle_storage& operator=(const handle_storage& other) noexcept = default; 44 | 45 | handle_storage(handle_storage&& other) noexcept 46 | : _handle(other._handle) 47 | { 48 | other.reset(); 49 | } 50 | 51 | handle_storage& operator=(handle_storage&& other) noexcept 52 | { 53 | _handle = other._handle; 54 | other.reset(); 55 | return *this; 56 | } 57 | 58 | bool valid() const noexcept { return _handle != -1; } 59 | 60 | void reset() noexcept { _handle = -1; } 61 | 62 | void reset(native_handle_t new_handle) noexcept { _handle = new_handle; } 63 | 64 | native_handle_t native() const noexcept { return _handle; } 65 | 66 | pid_t pid() const noexcept { return _handle; } 67 | 68 | inline pid_t pid(std::error_code&) const noexcept { return _handle; } 69 | }; // handle_storage 70 | 71 | }} // namespace jm::detail 72 | 73 | #endif // include guard 74 | -------------------------------------------------------------------------------- /include/process_handle/osx_storage.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef JM_PROCESS_HANDLE_STORAGE_APPLE_HPP 18 | #define JM_PROCESS_HANDLE_STORAGE_APPLE_HPP 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace jm { namespace detail { 26 | 27 | using pid_t = ::pid_t; 28 | using native_handle_t = ::mach_port_t; 29 | 30 | 31 | class handle_storage { 32 | native_handle_t _handle; 33 | 34 | public: 35 | explicit handle_storage() noexcept 36 | : _handle(::mach_task_self()) {} 37 | 38 | explicit handle_storage(native_handle_t handle) noexcept 39 | : _handle(handle) {} 40 | 41 | explicit handle_storage(pid_t pid) 42 | { 43 | const auto kr = ::task_for_pid(::mach_task_self(), pid, &_handle); 44 | if (kr != KERN_SUCCESS) 45 | throw std::system_error(std::error_code(kr, std::system_category()), "task_for_pid() failed"); 46 | } 47 | 48 | explicit handle_storage(pid_t pid, std::error_code& ec) noexcept 49 | { 50 | const auto kr = ::task_for_pid(::mach_task_self(), pid, &_handle); 51 | if (kr != KERN_SUCCESS) { 52 | reset(); 53 | ec = std::error_code(kr, std::system_category()); 54 | } 55 | } 56 | 57 | handle_storage(const handle_storage& other) noexcept = default; 58 | handle_storage& operator=(const handle_storage& other) noexcept = default; 59 | 60 | handle_storage(handle_storage&& other) noexcept 61 | : _handle(other._handle) 62 | { 63 | other.reset(); 64 | } 65 | 66 | handle_storage& operator=(handle_storage&& other) noexcept 67 | { 68 | _handle = other._handle; 69 | other.reset(); 70 | return *this; 71 | } 72 | 73 | bool valid() const noexcept { return static_cast(_handle); } 74 | 75 | void reset() noexcept { _handle = static_cast(0); } 76 | 77 | void reset(native_handle_t new_handle) noexcept { _handle = new_handle; } 78 | 79 | native_handle_t native() const noexcept { return _handle; } 80 | 81 | pid_t pid() const 82 | { 83 | pid_t pid; 84 | const auto kr = ::pid_for_task(_handle, &pid); 85 | if (kr != KERN_SUCCESS) 86 | throw std::system_error(std::error_code(kr, std::system_category()), "pid_for_task() failed"); 87 | 88 | return pid; 89 | } 90 | 91 | pid_t pid(std::error_code& ec) const noexcept 92 | { 93 | pid_t pid; 94 | const auto kr = ::pid_for_task(_handle, &pid); 95 | if (kr != KERN_SUCCESS) 96 | ec = ec = std::error_code(kr, std::system_category()); 97 | 98 | return pid; 99 | } 100 | }; // handle_storage 101 | 102 | }} // namespace jm::detail 103 | 104 | #endif // include guard 105 | -------------------------------------------------------------------------------- /include/process_handle/windows_storage.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef JM_PROCESS_HANDLE_STORAGE_WINDOWS_HPP 18 | #define JM_PROCESS_HANDLE_STORAGE_WINDOWS_HPP 19 | 20 | #include 21 | #include 22 | 23 | namespace jm { namespace detail { 24 | 25 | extern "C" { 26 | __declspec(dllimport) int __stdcall CloseHandle(void* handle); 27 | __declspec(dllimport) void* 28 | __stdcall OpenProcess(unsigned long desired_access, int inherit_handle, unsigned long process_id); 29 | __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); 30 | __declspec(dllimport) unsigned long __stdcall GetProcessId(void* handle); 31 | __declspec(dllimport) unsigned long __stdcall GetLastError(); 32 | } 33 | 34 | constexpr unsigned long SYNCHRONIZE_ = 0x00100000; 35 | constexpr unsigned long STANDARD_RIGHTS_REQUIRED_ = 0x000F0000; 36 | constexpr unsigned long PROCESS_ALL_ACCESS_ = (STANDARD_RIGHTS_REQUIRED_ | SYNCHRONIZE_ | 0xFFF); 37 | 38 | using pid_t = int; 39 | using native_handle_t = void*; 40 | 41 | class handle_storage { 42 | std::shared_ptr _handle; 43 | 44 | struct handle_deleter_t { 45 | inline void operator()(native_handle_t handle) noexcept 46 | { 47 | if (handle) 48 | CloseHandle(handle); 49 | } 50 | }; 51 | 52 | public: 53 | explicit handle_storage() 54 | : handle_storage(static_cast(GetCurrentProcessId())) {} 55 | 56 | explicit handle_storage(native_handle_t handle) 57 | : _handle(handle, handle_deleter_t{}) {} 58 | 59 | explicit handle_storage(pid_t pid) 60 | : handle_storage(OpenProcess(PROCESS_ALL_ACCESS_, 0, static_cast(pid))) 61 | { 62 | if (_handle.get() == nullptr) 63 | throw std::system_error(std::error_code(static_cast(GetLastError()), std::system_category()) 64 | , "OpenProcess() failed"); 65 | } 66 | 67 | explicit handle_storage(pid_t pid, std::error_code& ec) 68 | : handle_storage(OpenProcess(PROCESS_ALL_ACCESS_, 0, static_cast(pid))) 69 | { 70 | if (_handle.get() == nullptr) 71 | ec = std::error_code(static_cast(GetLastError()), std::system_category()); 72 | } 73 | 74 | handle_storage(const handle_storage& other) noexcept = default; 75 | handle_storage& operator=(const handle_storage& other) noexcept = default; 76 | 77 | handle_storage(handle_storage&& other) noexcept = default; 78 | handle_storage& operator=(handle_storage&& other) noexcept = default; 79 | 80 | bool valid() const noexcept { return static_cast(_handle); } 81 | 82 | void reset() noexcept { _handle.reset(); } 83 | 84 | void reset(native_handle_t new_handle) noexcept { _handle.reset(new_handle, handle_deleter_t{}); } 85 | 86 | native_handle_t native() const noexcept { return _handle.get(); } 87 | 88 | pid_t pid() const noexcept { return static_cast(GetProcessId(_handle.get())); } 89 | 90 | inline pid_t pid(std::error_code&) const noexcept { return pid(); } 91 | }; // handle_storage 92 | 93 | }} // namespace jm::detail 94 | 95 | #endif // include guard 96 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (CATCH_MODULE_PATH "${PROJECT_SOURCE_DIR}/test/Catch") 2 | set (CATCH_INCLUDE_PATH "${CATCH_MODULE_PATH}/include") 3 | 4 | #include custom cmake function 5 | include ("${CATCH_MODULE_PATH}/contrib/ParseAndAddCatchTests.cmake") 6 | 7 | #configure variables 8 | set (TEST_APP_NAME "process_handle_test") 9 | 10 | #configure directories 11 | set (TEST_MODULE_PATH "${PROJECT_SOURCE_DIR}/test") 12 | 13 | #set includes 14 | include_directories (${PROJECT_SOURCE_DIR}/include ${CATCH_INCLUDE_PATH}) 15 | 16 | #set test sources 17 | #file (GLOB TEST_SOURCE_FILES "$${CMAKE_CURRENT_LIST_DIR}/*.cpp") 18 | 19 | set (TEST_SOURCE_FILES 20 | ${TEST_MODULE_PATH}/main.cpp) 21 | 22 | #set target executable 23 | add_executable (${TEST_APP_NAME} ${TEST_SOURCE_FILES}) 24 | 25 | #add the library 26 | target_link_libraries (${TEST_APP_NAME} process_handle) 27 | 28 | # Turn on CMake testing capabilities 29 | enable_testing() 30 | 31 | #parse catch tests 32 | ParseAndAddCatchTests (${TEST_APP_NAME}) -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST_CASE("all the tests") 5 | { 6 | { 7 | jm::process_handle h; 8 | INFO("current process id: " << h.owner_id() << "\n native handle: " << h.native()); 9 | } 10 | 11 | SECTION("operator bool") 12 | { 13 | jm::process_handle h; 14 | REQUIRE(static_cast(h)); 15 | } 16 | 17 | SECTION("reset(std::nullptr_t)") 18 | { 19 | jm::process_handle h; 20 | h.reset(); 21 | } 22 | 23 | SECTION("reset(native_handle_t)") 24 | { 25 | jm::process_handle h; 26 | jm::process_handle h2; 27 | h.reset(h2.native()); 28 | REQUIRE(h.native() == h2.native()); 29 | h.reset(); 30 | } 31 | 32 | SECTION("assignment") 33 | { 34 | jm::process_handle h; 35 | jm::process_handle h2; 36 | 37 | h = h2; 38 | REQUIRE(h.native() == h2.native()); 39 | REQUIRE(h.owner_id() == h2.owner_id()); 40 | h = std::move(h2); 41 | REQUIRE_FALSE(static_cast(h2)); 42 | } 43 | 44 | SECTION("copy construction") 45 | { 46 | std::error_code ec; 47 | jm::process_handle h; 48 | jm::process_handle new_h(h); 49 | jm::process_handle new_h2(h.native()); 50 | REQUIRE(h.native() == new_h.native()); 51 | REQUIRE(h.native() == new_h2.native()); 52 | REQUIRE(h.owner_id() == new_h.owner_id()); 53 | REQUIRE(h.owner_id() == new_h2.owner_id()); 54 | REQUIRE(h.owner_id() == new_h.owner_id(ec)); 55 | REQUIRE(h.owner_id() == new_h2.owner_id(ec)); 56 | REQUIRE_FALSE(ec); 57 | } 58 | 59 | SECTION("move construction") 60 | { 61 | std::error_code ec; 62 | jm::process_handle h; 63 | jm::process_handle new_h(h); 64 | 65 | REQUIRE(h.native() == new_h.native()); 66 | jm::process_handle new_h2(std::move(new_h)); 67 | 68 | REQUIRE_FALSE(static_cast(new_h)); 69 | REQUIRE(static_cast(new_h2)); 70 | 71 | REQUIRE(h.owner_id() == new_h2.owner_id()); 72 | REQUIRE(h.owner_id() == new_h2.owner_id(ec)); 73 | REQUIRE_FALSE(ec); 74 | } 75 | 76 | SECTION("move construction") 77 | { 78 | std::error_code ec; 79 | jm::process_handle h; 80 | 81 | jm::process_handle new_h(h.owner_id()); 82 | jm::process_handle new_h2(h.owner_id(), ec); 83 | 84 | REQUIRE(h.owner_id() == new_h2.owner_id()); 85 | REQUIRE(h.owner_id() == new_h2.owner_id(ec)); 86 | } 87 | 88 | } --------------------------------------------------------------------------------