├── .Rbuildignore ├── .github ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── SUPPORT.md └── workflows │ ├── R-CMD-check.yaml │ ├── freebsd.yaml │ ├── openbsd.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ ├── rhel.yaml │ ├── rhub.yaml │ ├── s390x.yaml │ └── test-coverage.yaml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── LICENSE.note ├── NAMESPACE ├── NEWS.md ├── R ├── cleancall.R ├── compat-vctrs.R ├── disk.R ├── errno.R ├── error.R ├── glob.R ├── iso-date.R ├── kill-tree.R ├── linux.R ├── low-level.R ├── macos.R ├── memoize.R ├── memory.R ├── os.R ├── package.R ├── posix.R ├── ps-package.R ├── ps.R ├── rematch2.R ├── string.R ├── system.R ├── testthat-reporter.R └── utils.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── air.toml ├── cleanup ├── codecov.yml ├── configure ├── configure.win ├── cran-comments.md ├── header.md ├── inst ├── WORDLIST ├── internals.md └── tools │ ├── error-codes.R │ └── winver.R ├── man ├── CleanupReporter.Rd ├── errno.Rd ├── ps-package.Rd ├── ps.Rd ├── ps_apps.Rd ├── ps_boot_time.Rd ├── ps_children.Rd ├── ps_cmdline.Rd ├── ps_connections.Rd ├── ps_cpu_count.Rd ├── ps_cpu_times.Rd ├── ps_create_time.Rd ├── ps_cwd.Rd ├── ps_descent.Rd ├── ps_disk_io_counters.Rd ├── ps_disk_partitions.Rd ├── ps_disk_usage.Rd ├── ps_environ.Rd ├── ps_exe.Rd ├── ps_fs_info.Rd ├── ps_fs_mount_point.Rd ├── ps_fs_stat.Rd ├── ps_get_cpu_affinity.Rd ├── ps_get_nice.Rd ├── ps_handle.Rd ├── ps_interrupt.Rd ├── ps_is_running.Rd ├── ps_kill.Rd ├── ps_kill_tree.Rd ├── ps_loadavg.Rd ├── ps_memory_info.Rd ├── ps_name.Rd ├── ps_num_fds.Rd ├── ps_num_threads.Rd ├── ps_open_files.Rd ├── ps_os_type.Rd ├── ps_pid.Rd ├── ps_pids.Rd ├── ps_ppid.Rd ├── ps_resume.Rd ├── ps_send_signal.Rd ├── ps_shared_lib_users.Rd ├── ps_shared_libs.Rd ├── ps_status.Rd ├── ps_string.Rd ├── ps_suspend.Rd ├── ps_system_cpu_times.Rd ├── ps_system_memory.Rd ├── ps_system_swap.Rd ├── ps_terminal.Rd ├── ps_terminate.Rd ├── ps_tty_size.Rd ├── ps_uids.Rd ├── ps_username.Rd ├── ps_users.Rd ├── ps_wait.Rd └── signals.Rd ├── ps.Rproj ├── src ├── .gitignore ├── Makevars.in ├── api-common.c ├── api-linux.c ├── api-macos.c ├── api-posix.c ├── api-windows-conn.c ├── api-windows.c ├── arch │ ├── macos │ │ ├── apps.m │ │ ├── disk.c │ │ ├── process_info.c │ │ └── process_info.h │ └── windows │ │ ├── ntextapi.h │ │ ├── process_handles.c │ │ ├── process_handles.h │ │ ├── process_info.c │ │ ├── process_info.h │ │ └── wmi.c ├── cleancall.c ├── cleancall.h ├── common.c ├── common.h ├── dummy.c ├── extra.c ├── init.c ├── install.libs.R ├── interrupt.c ├── linux.c ├── macos.c ├── posix.c ├── posix.h ├── ps-internal.h ├── ps.h ├── px.c ├── windows.c └── windows.h ├── tests ├── testthat.R └── testthat │ ├── _snaps │ └── common.md │ ├── fixtures │ └── cleanup-error │ │ └── test-cleanup-error.R │ ├── helpers.R │ ├── test-cleanup-reporter.R │ ├── test-common.R │ ├── test-connections.R │ ├── test-disk.R │ ├── test-finished.R │ ├── test-kill-tree.R │ ├── test-linux.R │ ├── test-macos.R │ ├── test-pid-reuse.R │ ├── test-posix-zombie.R │ ├── test-posix.R │ ├── test-ps.R │ ├── test-system.R │ ├── test-utils.R │ ├── test-wait-inotify.R │ ├── test-wait.R │ ├── test-windows.R │ └── test-winver.R └── tools └── linux-fs-types.txt /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^\.github$ 2 | ^\.travis\.yml$ 3 | ^codecov\.yml$ 4 | ^appveyor\.yml$ 5 | ^src/Makevars$ 6 | ^src/config\.h$ 7 | .o$ 8 | ^README\.Rmd$ 9 | ^README\.html$ 10 | ^.*\.dSYM$ 11 | ^src/px$ 12 | ^src/px\.exe$ 13 | ^src/interrupt\.exe$ 14 | ^docs$ 15 | ^_pkgdown\.yml$ 16 | ^cran-comments\.md$ 17 | ^revdep$ 18 | ^header\.md$ 19 | ^\.Rproj\.user$ 20 | ^.*\.Rproj$ 21 | ^pkgdown$ 22 | ^LICENSE\.md$ 23 | ^[\.]?air\.toml$ 24 | ^\.vscode$ 25 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ps 2 | 3 | This outlines how to propose a change to ps. For more detailed 4 | info about contributing to this, and other tidyverse packages, please see the 5 | [**development contributing guide**](https://rstd.io/tidy-contrib). 6 | 7 | ### Fixing typos 8 | 9 | Small typos or grammatical errors in documentation may be edited directly using 10 | the GitHub web interface, so long as the changes are made in the _source_ file. 11 | 12 | * YES: you edit a roxygen comment in a `.R` file below `R/`. 13 | * NO: you edit an `.Rd` file below `man/`. 14 | 15 | ### Prerequisites 16 | 17 | Before you make a substantial pull request, you should always file an issue and 18 | make sure someone from the team agrees that it’s a problem. If you’ve found a 19 | bug, create an associated issue and illustrate the bug with a minimal 20 | [reprex](https://www.tidyverse.org/help/#reprex). 21 | 22 | ### Pull request process 23 | 24 | * We recommend that you create a Git branch for each pull request (PR). 25 | * Look at the Travis and AppVeyor build status before and after making changes. 26 | The `README` should contain badges for any continuous integration services used 27 | by the package. 28 | * New code should follow the tidyverse [style guide](http://style.tidyverse.org). 29 | You can use the [styler](https://CRAN.R-project.org/package=styler) package to 30 | apply these styles, but please don't restyle code that has nothing to do with 31 | your PR. 32 | * We use [roxygen2](https://cran.r-project.org/package=roxygen2), with 33 | [Markdown syntax](https://roxygen2.r-lib.org/articles/rd-formatting.html), 34 | for documentation. 35 | * We use [testthat](https://cran.r-project.org/package=testthat). Contributions 36 | with test cases included are easier to accept. 37 | * For user-facing changes, add a bullet to the top of `NEWS.md` below the current 38 | development version header describing the changes made followed by your GitHub 39 | username, and links to relevant issue(s)/PR(s). 40 | 41 | ### Code of Conduct 42 | 43 | Please note that this project is released with a [Contributor Code of 44 | Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to 45 | abide by its terms. 46 | 47 | ### See tidyverse [development contributing guide](https://rstd.io/tidy-contrib) for further details. 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please briefly describe your problem and what output you expect. If you have a question, please don't use this form. Instead, ask on or . 2 | 3 | Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](http://reprex.tidyverse.org/) before, start by reading . 4 | 5 | --- 6 | 7 | Brief description of the problem 8 | 9 | ```r 10 | # insert reprex here 11 | ``` 12 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Getting help with ps 2 | 3 | Thanks for using ps. Before filing an issue, there are a few places 4 | to explore and pieces to put together to make the process as smooth as possible. 5 | 6 | Start by making a minimal **repr**oducible **ex**ample using the 7 | [reprex](http://reprex.tidyverse.org/) package. If you haven't heard of or used 8 | reprex before, you're in for a treat! Seriously, reprex will make all of your 9 | R-question-asking endeavors easier (which is a pretty insane ROI for the five to 10 | ten minutes it'll take you to learn what it's all about). For additional reprex 11 | pointers, check out the [Get help!](https://www.tidyverse.org/help/) section of 12 | the tidyverse site. 13 | 14 | Armed with your reprex, the next step is to figure out [where to ask](https://www.tidyverse.org/help/#where-to-ask). 15 | 16 | * If it's a question: start with [community.rstudio.com](https://community.rstudio.com/), 17 | and/or StackOverflow. There are more people there to answer questions. 18 | * If it's a bug: you're in the right place, file an issue. 19 | * If you're not sure: let the community help you figure it out! If your 20 | problem _is_ a bug or a feature request, you can easily return here and 21 | report it. 22 | 23 | Before opening a new issue, be sure to [search issues and pull requests](https://github.com/tidyverse/ps/issues) to make sure the 24 | bug hasn't been reported and/or already fixed in the development version. By 25 | default, the search will be pre-populated with `is:issue is:open`. You can 26 | [edit the qualifiers](https://help.github.com/articles/searching-issues-and-pull-requests/) 27 | (e.g. `is:pr`, `is:closed`) as needed. For example, you'd simply 28 | remove `is:open` to search _all_ issues in the repo, open or closed. 29 | 30 | 31 | If you _are_ in the right place, and need to file an issue, please review the 32 | ["File issues"](https://www.tidyverse.org/contribute/#issues) paragraph from 33 | the tidyverse contributing guidelines. 34 | 35 | Thanks for your help! 36 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | workflow_dispatch: 12 | 13 | name: R-CMD-check.yaml 14 | 15 | permissions: read-all 16 | 17 | jobs: 18 | R-CMD-check: 19 | runs-on: ${{ matrix.config.os }} 20 | 21 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | config: 27 | - {os: macos-15, r: 'devel'} 28 | - {os: macos-latest, r: 'devel'} 29 | - {os: macos-latest, r: 'release'} 30 | 31 | - {os: windows-latest, r: 'release'} 32 | # use 4.0 or 4.1 to check with rtools40's older compiler 33 | - {os: windows-latest, r: 'oldrel-4'} 34 | - {os: windows-latest, r: '3.6.3'} 35 | 36 | - {os: ubuntu-latest, r: 'devel' } 37 | - {os: ubuntu-22.04-arm, r: 'release' } 38 | - {os: ubuntu-24.04-arm, r: 'release' } 39 | - {os: ubuntu-latest, r: 'release'} 40 | - {os: ubuntu-latest, r: 'oldrel-1'} 41 | - {os: ubuntu-latest, r: 'oldrel-2'} 42 | - {os: ubuntu-latest, r: 'oldrel-3'} 43 | - {os: ubuntu-latest, r: 'oldrel-4'} 44 | 45 | env: 46 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 47 | R_KEEP_PKG_SOURCE: yes 48 | 49 | steps: 50 | - uses: actions/checkout@v4 51 | 52 | - uses: r-lib/actions/setup-pandoc@v2 53 | 54 | - uses: r-lib/actions/setup-r@v2 55 | with: 56 | r-version: ${{ matrix.config.r }} 57 | use-public-rspm: true 58 | 59 | - uses: r-lib/actions/setup-r-dependencies@v2 60 | with: 61 | extra-packages: any::rcmdcheck 62 | needs: check 63 | 64 | - uses: r-lib/actions/check-r-package@v2 65 | with: 66 | upload-snapshots: true 67 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 68 | -------------------------------------------------------------------------------- /.github/workflows/freebsd.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main, master] 4 | pull_request: 5 | workflow_dispatch: 6 | inputs: 7 | release: 8 | description: 'FreeBSD release' 9 | required: true 10 | type: choice 11 | options: 12 | - '15.0' 13 | - '14.2-pre' 14 | - '14.1' 15 | - '14.0' 16 | - '13.4' 17 | - '13.3' 18 | - '13.2' 19 | - '12.4' 20 | default: '14.1' 21 | 22 | name: freebsd.yaml 23 | 24 | jobs: 25 | freebsd: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | - uses: r-hub/actions/setup-r-freebsd@main 30 | with: 31 | release: ${{ github.event.inputs.release || '14.1' }} 32 | - uses: r-hub/actions/platform-info@v1 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | pak-version: none 37 | install-pandoc: false 38 | install-quarto: false 39 | extra-packages: any::rcmdcheck 40 | needs: check 41 | 42 | - uses: r-lib/actions/check-r-package@v2 43 | with: 44 | upload-snapshots: true 45 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 46 | -------------------------------------------------------------------------------- /.github/workflows/openbsd.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main, master] 4 | pull_request: 5 | workflow_dispatch: 6 | inputs: 7 | release: 8 | description: 'OpenBSD release' 9 | required: true 10 | type: choice 11 | options: 12 | - '7.6' 13 | - '7.5' 14 | - '7.4' 15 | default: '7.6' 16 | 17 | name: openbsd.yaml 18 | 19 | jobs: 20 | openbsd: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: r-hub/actions/setup-r-openbsd@v1 25 | with: 26 | release: ${{ github.event.inputs.release || '7.6' }} 27 | - uses: r-hub/actions/platform-info@v1 28 | 29 | - name: Install system packages (for pingr) 30 | run: | 31 | pkg_add -I libbind 32 | cd /usr/local/lib && ln -s libbind/libbind.so* . 33 | shell: openbsd {0} 34 | 35 | - uses: r-lib/actions/setup-r-dependencies@v2 36 | with: 37 | pak-version: none 38 | install-pandoc: false 39 | install-quarto: false 40 | extra-packages: any::rcmdcheck 41 | needs: check 42 | 43 | - uses: r-lib/actions/check-r-package@v2 44 | with: 45 | upload-snapshots: true 46 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 47 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | release: 8 | types: [published] 9 | workflow_dispatch: 10 | 11 | name: pkgdown.yaml 12 | 13 | permissions: read-all 14 | 15 | jobs: 16 | pkgdown: 17 | runs-on: ubuntu-latest 18 | # Only restrict concurrency for non-PR jobs 19 | concurrency: 20 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 21 | env: 22 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 23 | permissions: 24 | contents: write 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - uses: r-lib/actions/setup-pandoc@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | use-public-rspm: true 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | extra-packages: any::pkgdown, local::. 37 | needs: website 38 | 39 | - name: Build site 40 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 41 | shell: Rscript {0} 42 | 43 | - name: Deploy to GitHub pages 🚀 44 | if: github.event_name != 'pull_request' 45 | uses: JamesIves/github-pages-deploy-action@v4.5.0 46 | with: 47 | clean: false 48 | branch: gh-pages 49 | folder: docs 50 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: pr-commands.yaml 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | document: 13 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 14 | name: document 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | permissions: 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: r-lib/actions/pr-fetch@v2 24 | with: 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::roxygen2 34 | needs: pr-document 35 | 36 | - name: Document 37 | run: roxygen2::roxygenise() 38 | shell: Rscript {0} 39 | 40 | - name: commit 41 | run: | 42 | git config --local user.name "$GITHUB_ACTOR" 43 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 44 | git add man/\* NAMESPACE 45 | git commit -m 'Document' 46 | 47 | - uses: r-lib/actions/pr-push@v2 48 | with: 49 | repo-token: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | style: 52 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 53 | name: style 54 | runs-on: ubuntu-latest 55 | env: 56 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 57 | permissions: 58 | contents: write 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | - uses: r-lib/actions/pr-fetch@v2 63 | with: 64 | repo-token: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | - uses: r-lib/actions/setup-r@v2 67 | 68 | - name: Install dependencies 69 | run: install.packages("styler") 70 | shell: Rscript {0} 71 | 72 | - name: Style 73 | run: styler::style_pkg() 74 | shell: Rscript {0} 75 | 76 | - name: commit 77 | run: | 78 | git config --local user.name "$GITHUB_ACTOR" 79 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 80 | git add \*.R 81 | git commit -m 'Style' 82 | 83 | - uses: r-lib/actions/pr-push@v2 84 | with: 85 | repo-token: ${{ secrets.GITHUB_TOKEN }} 86 | -------------------------------------------------------------------------------- /.github/workflows/rhel.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | 4 | name: rhel.yaml 5 | 6 | permissions: read-all 7 | 8 | jobs: 9 | rhel: 10 | runs-on: ubuntu-latest 11 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | config: 16 | - { os: rhel7, r: 'release', key: '${{ secrets.REDHAT_ACTIVATION_KEY_RHEL7 }}' } 17 | - { os: rhel8, r: 'release', key: '${{ secrets.REDHAT_ACTIVATION_KEY_RHEL8 }}' } 18 | container: 19 | image: ghcr.io/r-hub/containers/${{ matrix.config.os }}:latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Register 25 | run: | 26 | subscription-manager register \ 27 | --org ${{ secrets.REDHAT_ORG }} \ 28 | --activationkey ${{ matrix.config.key }} 29 | shell: bash 30 | 31 | - name: Install R 32 | run: | 33 | rig add ${{ matrix.config.r }} 34 | shell: bash 35 | 36 | - uses: r-lib/actions/setup-r-dependencies@v2 37 | with: 38 | extra-packages: any::rcmdcheck 39 | needs: check 40 | 41 | - uses: r-lib/actions/check-r-package@v2 42 | with: 43 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 44 | env: 45 | NOT_CRAN: true 46 | 47 | - name: Unregister 48 | if: always() 49 | run: | 50 | subscription-manager unregister || true 51 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: rhub.yaml 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@main 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@main 55 | - uses: r-hub/actions/platform-info@main 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/actions/setup-deps@main 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/run-check@main 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | steps: 79 | - uses: r-hub/actions/checkout@main 80 | - uses: r-hub/actions/setup-r@main 81 | with: 82 | job-config: ${{ matrix.config.job-config }} 83 | token: ${{ secrets.RHUB_TOKEN }} 84 | - uses: r-hub/actions/platform-info@main 85 | with: 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | job-config: ${{ matrix.config.job-config }} 88 | - uses: r-hub/actions/setup-deps@main 89 | with: 90 | job-config: ${{ matrix.config.job-config }} 91 | token: ${{ secrets.RHUB_TOKEN }} 92 | - uses: r-hub/actions/run-check@main 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | -------------------------------------------------------------------------------- /.github/workflows/s390x.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | 4 | name: s390x.yaml 5 | 6 | jobs: 7 | s390x: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - uses: r-hub/actions/ctr-start@main 12 | with: 13 | image: ghcr.io/r-hub/containers/s390x 14 | platform: linux/s390x 15 | ctr-name: s390x 16 | 17 | - name: Test R in container 18 | run: | 19 | getRversion() 20 | R.version[["platform"]] 21 | shell: Rscript {0} 22 | 23 | - uses: r-lib/actions/setup-r-dependencies@v2 24 | with: 25 | pak-version: none 26 | cache-version: s390x-1 27 | extra-packages: any::rcmdcheck 28 | needs: check 29 | 30 | - uses: r-lib/actions/check-r-package@v2 31 | with: 32 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 33 | upload-results: never 34 | upload-snapshots: false 35 | env: 36 | NOT_CRAN: true 37 | 38 | - uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: ${{ format('{0}-{1}-results', runner.os, runner.arch) }} 42 | path: check 43 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | 8 | name: test-coverage.yaml 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | test-coverage: 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - uses: r-lib/actions/setup-r@v2 22 | with: 23 | use-public-rspm: true 24 | 25 | - uses: r-lib/actions/setup-r-dependencies@v2 26 | with: 27 | extra-packages: any::covr, any::xml2 28 | needs: coverage 29 | 30 | - name: Test coverage 31 | run: | 32 | cov <- covr::package_coverage( 33 | quiet = FALSE, 34 | clean = FALSE, 35 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 36 | ) 37 | print(cov) 38 | covr::to_cobertura(cov) 39 | shell: Rscript {0} 40 | 41 | - uses: codecov/codecov-action@v5 42 | with: 43 | # Fail if error if not on PR, or if on PR and token is given 44 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} 45 | files: ./cobertura.xml 46 | plugins: noop 47 | disable_search: true 48 | token: ${{ secrets.CODECOV_TOKEN }} 49 | 50 | - name: Show testthat output 51 | if: always() 52 | run: | 53 | ## -------------------------------------------------------------------- 54 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 55 | shell: bash 56 | 57 | - name: Upload test results 58 | if: failure() 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: coverage-test-failures 62 | path: ${{ runner.temp }}/package 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rhistory 2 | .RData 3 | .Rproj.user 4 | /src/Makevars 5 | /src/config.h 6 | /README.html 7 | /src/*.dSYM 8 | /src/px 9 | /src/px.exe 10 | /src/interrupt.exe 11 | /src-i386 12 | /src-x64 13 | /src/error-codes.c 14 | /revdep 15 | /docs 16 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Posit.air-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[r]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "Posit.air-vscode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ps 2 | Title: List, Query, Manipulate System Processes 3 | Version: 1.9.1.9001 4 | Authors@R: c( 5 | person("Jay", "Loden", role = "aut"), 6 | person("Dave", "Daeschler", role = "aut"), 7 | person("Giampaolo", "Rodola'", role = "aut"), 8 | person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")), 9 | person("Posit Software, PBC", role = c("cph", "fnd"), 10 | comment = c(ROR = "03wc8by49")) 11 | ) 12 | Description: List, query and manipulate all system processes, on 13 | 'Windows', 'Linux' and 'macOS'. 14 | License: MIT + file LICENSE 15 | URL: https://github.com/r-lib/ps, https://ps.r-lib.org/ 16 | BugReports: https://github.com/r-lib/ps/issues 17 | Depends: 18 | R (>= 3.4) 19 | Imports: 20 | utils 21 | Suggests: 22 | callr, 23 | covr, 24 | curl, 25 | pillar, 26 | pingr, 27 | processx (>= 3.1.0), 28 | R6, 29 | rlang, 30 | testthat (>= 3.0.0), 31 | webfakes, 32 | withr 33 | Biarch: true 34 | Config/Needs/website: tidyverse/tidytemplate 35 | Config/testthat/edition: 3 36 | Config/usethis/last-upkeep: 2025-04-28 37 | Encoding: UTF-8 38 | Roxygen: list(markdown = TRUE) 39 | RoxygenNote: 7.3.2 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2025 2 | COPYRIGHT HOLDER: ps authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2025 ps authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.note: -------------------------------------------------------------------------------- 1 | ps is based on psutil, which is under the BSD (3 clause) license. 2 | See its full license here: 3 | https://github.com/giampaolo/psutil/blob/master/LICENSE 4 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as.character,ps_handle) 4 | S3method(format,ps_handle) 5 | S3method(print,ps_handle) 6 | S3method(print,with_process_cleanup) 7 | export(CleanupReporter) 8 | export(errno) 9 | export(ps) 10 | export(ps_apps) 11 | export(ps_boot_time) 12 | export(ps_children) 13 | export(ps_cmdline) 14 | export(ps_connections) 15 | export(ps_cpu_count) 16 | export(ps_cpu_times) 17 | export(ps_create_time) 18 | export(ps_cwd) 19 | export(ps_descent) 20 | export(ps_disk_io_counters) 21 | export(ps_disk_partitions) 22 | export(ps_disk_usage) 23 | export(ps_environ) 24 | export(ps_environ_raw) 25 | export(ps_exe) 26 | export(ps_find_tree) 27 | export(ps_fs_info) 28 | export(ps_fs_mount_point) 29 | export(ps_fs_stat) 30 | export(ps_get_cpu_affinity) 31 | export(ps_get_nice) 32 | export(ps_gids) 33 | export(ps_handle) 34 | export(ps_interrupt) 35 | export(ps_is_running) 36 | export(ps_is_supported) 37 | export(ps_kill) 38 | export(ps_kill_tree) 39 | export(ps_loadavg) 40 | export(ps_mark_tree) 41 | export(ps_memory_full_info) 42 | export(ps_memory_info) 43 | export(ps_name) 44 | export(ps_num_fds) 45 | export(ps_num_threads) 46 | export(ps_open_files) 47 | export(ps_os_type) 48 | export(ps_parent) 49 | export(ps_pid) 50 | export(ps_pids) 51 | export(ps_ppid) 52 | export(ps_resume) 53 | export(ps_send_signal) 54 | export(ps_set_cpu_affinity) 55 | export(ps_set_nice) 56 | export(ps_shared_lib_users) 57 | export(ps_shared_libs) 58 | export(ps_status) 59 | export(ps_string) 60 | export(ps_suspend) 61 | export(ps_system_cpu_times) 62 | export(ps_system_memory) 63 | export(ps_system_swap) 64 | export(ps_terminal) 65 | export(ps_terminate) 66 | export(ps_tty_size) 67 | export(ps_uids) 68 | export(ps_username) 69 | export(ps_users) 70 | export(ps_wait) 71 | export(ps_windows_nice_values) 72 | export(signals) 73 | export(with_process_cleanup) 74 | importFrom(utils,head) 75 | importFrom(utils,read.delim) 76 | importFrom(utils,read.table) 77 | importFrom(utils,tail) 78 | useDynLib(ps, .registration = TRUE) 79 | -------------------------------------------------------------------------------- /R/cleancall.R: -------------------------------------------------------------------------------- 1 | call_with_cleanup <- function(ptr, ...) { 2 | .Call(cleancall_call, pairlist(ptr, ...), parent.frame()) 3 | } 4 | -------------------------------------------------------------------------------- /R/errno.R: -------------------------------------------------------------------------------- 1 | #' List of 'errno' error codes 2 | #' 3 | #' For the errors that are not used on the current platform, `value` is 4 | #' `NA_integer_`. 5 | #' 6 | #' A data frame with columns: `name`, `value`, `description`. 7 | #' @export 8 | #' @examplesIf ps::ps_is_supported() && ! ps:::is_cran_check() 9 | #' errno() 10 | 11 | errno <- function() { 12 | err <- as.list(ps_env$constants$errno) 13 | err <- err[order(names(err))] 14 | data_frame( 15 | name = names(err), 16 | value = vapply(err, "[[", integer(1), 1), 17 | description = vapply(err, "[[", character(1), 2) 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /R/error.R: -------------------------------------------------------------------------------- 1 | ps__invalid_argument <- function(arg, ...) { 2 | msg <- paste0(encodeString(arg, quote = "`"), ...) 3 | structure( 4 | list(message = msg), 5 | class = c("invalid_argument", "error", "condition") 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /R/glob.R: -------------------------------------------------------------------------------- 1 | glob <- local({ 2 | to_regex <- function(glob) { 3 | restr <- new.env(parent = emptyenv(), size = 1003) 4 | idx <- 0L 5 | chr <- strsplit(glob, "", fixed = TRUE)[[1]] 6 | in_group <- FALSE 7 | 8 | for (c in chr) { 9 | if (c %in% c("/", "$", "^", "+", ".", "(", ")", "=", "!", "|")) { 10 | idx <- idx + 1L 11 | restr[[as.character(idx)]] <- paste0("\\", c) 12 | } else if (c == "?") { 13 | idx <- idx + 1L 14 | restr[[as.character(idx)]] <- "." 15 | } else if (c == "[" || c == "]") { 16 | idx <- idx + 1L 17 | restr[[as.character(idx)]] <- c 18 | } else if (c == "{") { 19 | idx <- idx + 1L 20 | restr[[as.character(idx)]] <- "(" 21 | in_group <- TRUE 22 | } else if (c == "}") { 23 | idx <- idx + 1L 24 | restr[[as.character(idx)]] <- ")" 25 | in_group <- FALSE 26 | } else if (c == ",") { 27 | idx <- idx + 1L 28 | restr[[as.character(idx)]] <- if (in_group) "|" else paste0("\\", c) 29 | } else if (c == "*") { 30 | idx <- idx + 1L 31 | restr[[as.character(idx)]] <- ".*" 32 | } else { 33 | idx <- idx + 1L 34 | restr[[as.character(idx)]] <- c 35 | } 36 | } 37 | 38 | paste0( 39 | "^", 40 | paste(mget(as.character(seq_len(idx)), restr), collapse = ""), 41 | "$" 42 | ) 43 | } 44 | 45 | test <- function(glob, paths) { 46 | re <- to_regex(glob) 47 | grepl(re, paths) 48 | } 49 | 50 | test_any <- function(globs, paths) { 51 | if (!length(paths)) return(logical()) 52 | res <- vapply(globs, to_regex, character(1)) 53 | m <- matrix( 54 | as.logical(unlist(lapply(res, grepl, x = paths))), 55 | nrow = length(paths) 56 | ) 57 | apply(m, 1, any) 58 | } 59 | 60 | structure( 61 | list( 62 | .internal = environment(), 63 | to_regex = to_regex, 64 | test = test, 65 | test_any = test_any 66 | ), 67 | class = c("standalone_glob", "standalone") 68 | ) 69 | }) 70 | -------------------------------------------------------------------------------- /R/macos.R: -------------------------------------------------------------------------------- 1 | #' List currently running applications 2 | #' 3 | #' This function currently only works on macOS. 4 | #' 5 | #' @return A data frame with columns: 6 | #' - `pid`: integer process id. 7 | #' - `name`: process name. 8 | #' - `bundle_identifier`: bundle identifier, e.g. `com.apple.dock`. 9 | #' - `bundle_url`: bundle URL, a `file://` URL to the app bundle. 10 | #' - `arch`: executable architecture, possible values are 11 | #' `r paste(macos_archs$name, collapse = ", ")`. 12 | #' - `executable_url`: `file://` URL to the executable file. 13 | #' - `launch_date`: launch time stamp, a `POSIXct` object, may be `NA`. 14 | #' - `finished_launching`: whether the app has finished launching. 15 | #' - `active`: whether the app is active. 16 | #' - `activation_policy`: one of the following values: 17 | #' * `regular`: the application is an ordinary app that appears in the 18 | #' Dock and may have a user interface. 19 | #' * `accessory`: the application doesn’t appear in the Dock and 20 | #' doesn’t have a menu bar, but it may be activated programmatically 21 | #' or by clicking on one of its windows. 22 | #' * `prohibited`: the application doesn’t appear in the Dock and may 23 | #' not create windows or be activated. 24 | #' 25 | #' @export 26 | #' @examplesIf ps_is_supported() && ps_os_type()[["MACOS"]] && !ps:::is_cran_check() 27 | #' ps_apps() 28 | 29 | ps_apps <- function() { 30 | if (!ps_os_type()[["MACOS"]]) { 31 | stop("'ps_apps()' is only implemented on macOS") 32 | } 33 | tab <- as_data_frame(.Call(ps__list_apps)) 34 | 35 | tab <- tab[, c("pid", setdiff(names(tab), "pid"))] 36 | tab[["arch"]] <- macos_archs$name[match(tab[["arch"]], macos_archs$code)] 37 | tab[["launch_date"]] <- parse_iso_8601( 38 | sub(" +", "+", fixed = TRUE, tab[["launch_date"]]) 39 | ) 40 | # drop the ones without a pid, they are clearly (?) not running 41 | tab <- tab[tab$pid != -1, ] 42 | tab 43 | } 44 | 45 | macos_archs <- data.frame( 46 | name = c("arm64", "i386", "x86_64", "ppc", "ppc64"), 47 | code = c(0x0100000c, 0x00000007, 0x01000007, 0x00000012, 0x01000012) 48 | ) 49 | 50 | ps_status_macos_ps <- function(pids) { 51 | stopifnot(is.integer(pids)) 52 | suppressWarnings(tryCatch( 53 | { 54 | out <- system2( 55 | "/bin/ps", 56 | c("-o", "pid,stat", "-p", paste(pids, collapse = ",")), 57 | stdout = TRUE, 58 | stderr = FALSE 59 | ) 60 | out <- out[-1] 61 | out <- trimws(out) 62 | out2 <- strsplit(out, " ") 63 | opids <- map_int(out2, function(x) as.integer(x[[1]])) 64 | state <- map_chr(out2, function(x) substr(x[[2]], 1, 1)) 65 | state <- macos_process_states[state] 66 | unname(state[match(pids, opids)]) 67 | }, 68 | error = function(e) rep(NA_character_, length(pids)) 69 | )) 70 | } 71 | 72 | # From `man 1 ps` 73 | # I Marks a process that is idle (sleeping for longer than about 20 seconds). 74 | # R Marks a runnable process. 75 | # S Marks a process that is sleeping for less than about 20 seconds. 76 | # T Marks a stopped process. 77 | # U Marks a process in uninterruptible wait. 78 | # Z Marks a dead process (a “zombie”). 79 | 80 | macos_process_states <- c( 81 | I = "idle", 82 | R = "running", 83 | S = "sleeping", 84 | T = "stopped", 85 | U = "uninterruptible", 86 | Z = "zombie" 87 | ) 88 | -------------------------------------------------------------------------------- /R/memoize.R: -------------------------------------------------------------------------------- 1 | ## nocov start 2 | memoize <- function(fun) { 3 | fun 4 | cache <- NULL 5 | if (length(formals(fun)) > 0) { 6 | stop("Only memoizing functions without arguments") 7 | } 8 | dec <- function() { 9 | if (is.null(cache)) cache <<- fun() 10 | cache 11 | } 12 | attr(dec, "clear") <- function() cache <<- TRUE 13 | class(dec) <- c("memoize", class(dec)) 14 | dec 15 | } 16 | 17 | `$.memoize` <- function(x, name) { 18 | switch( 19 | name, 20 | "clear" = attr(x, "clear"), 21 | stop("unknown memoize method") 22 | ) 23 | } 24 | ## nocov end 25 | -------------------------------------------------------------------------------- /R/os.R: -------------------------------------------------------------------------------- 1 | #' Query the type of the OS 2 | #' 3 | #' @return `ps_os_type` returns a named logical vector. The rest of the 4 | #' functions return a logical scalar. 5 | #' 6 | #' `ps_is_supported()` returns `TRUE` if ps supports the current platform. 7 | #' 8 | #' @export 9 | #' @examples 10 | #' ps_os_type() 11 | #' ps_is_supported() 12 | 13 | ps_os_type <- function() { 14 | if (is.null(ps_env$os_type)) ps_env$os_type <- .Call(ps__os_type) 15 | ps_env$os_type 16 | } 17 | 18 | ps_os_name <- function() { 19 | os <- ps_os_type() 20 | os <- os[setdiff(names(os), c("BSD", "POSIX"))] 21 | names(os)[which(os)] 22 | } 23 | 24 | #' @rdname ps_os_type 25 | #' @export 26 | 27 | ps_is_supported <- function() { 28 | os <- ps_os_type() 29 | if (os[["LINUX"]]) { 30 | # On Linux we need to check if /proc is readable 31 | supported <- FALSE 32 | tryCatch( 33 | { 34 | readLines("/proc/stat", warn = FALSE, n = 1) 35 | supported <- TRUE 36 | }, 37 | error = function(e) e 38 | ) 39 | supported 40 | } else { 41 | os <- os[setdiff(names(os), c("BSD", "POSIX"))] 42 | any(os) 43 | } 44 | } 45 | 46 | supported_str <- function() { 47 | os <- ps_os_type() 48 | os <- os[setdiff(names(os), c("BSD", "POSIX"))] 49 | paste(caps(names(os)), collapse = ", ") 50 | } 51 | -------------------------------------------------------------------------------- /R/package.R: -------------------------------------------------------------------------------- 1 | ps_env <- new.env(parent = emptyenv()) 2 | 3 | Internal <- NULL 4 | 5 | ## nocov start 6 | .onLoad <- function(libname, pkgname) { 7 | ps_env$constants <- new.env(parent = emptyenv()) 8 | .Call(ps__init, asNamespace("ps"), ps_env$constants) 9 | if (!is.null(ps_env$constants$signals)) { 10 | ps_env$constants$signals <- as.list(ps_env$constants$signals) 11 | } 12 | if (!is.null(ps_env$constants$errno)) { 13 | ps_env$constants$errno <- as.list(ps_env$constants$errno) 14 | } 15 | if (!is.null(ps_env$constants$address_families)) { 16 | ps_env$constants$address_families <- 17 | as.list(ps_env$constants$address_families) 18 | } 19 | if (!is.null(ps_env$constants$socket_types)) { 20 | ps_env$constants$socket_types <- 21 | as.list(ps_env$constants$socket_types) 22 | } 23 | 24 | Internal <<- get(".Internal", asNamespace("base")) 25 | 26 | ps_boot_time <<- memoize(ps_boot_time) 27 | ps_cpu_count_logical <<- memoize(ps_cpu_count_logical) 28 | ps_cpu_count_physical <<- memoize(ps_cpu_count_physical) 29 | get_terminal_map <<- memoize(get_terminal_map) 30 | NA_time <<- memoize(NA_time) 31 | } 32 | ## nocov end 33 | 34 | utils::globalVariables(c("self", "super")) 35 | -------------------------------------------------------------------------------- /R/posix.R: -------------------------------------------------------------------------------- 1 | #' List of all supported signals 2 | #' 3 | #' Only the signals supported by the current platform are included. 4 | #' @return List of integers, named by signal names. 5 | #' 6 | #' @export 7 | 8 | signals <- function() { 9 | as.list(ps_env$constants$signals) 10 | } 11 | 12 | get_terminal_map <- function() { 13 | ls <- c( 14 | dir("/dev", pattern = "^tty.*", full.names = TRUE), 15 | dir("/dev/pts", full.names = TRUE) 16 | ) 17 | ret <- structure(ls, names = as.character(.Call(psp__stat_st_rdev, ls))) 18 | ret[names(ret) != "0"] 19 | } 20 | -------------------------------------------------------------------------------- /R/ps-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | #' @aliases ps-package 3 | "_PACKAGE" 4 | 5 | ## usethis namespace: start 6 | ## usethis namespace: end 7 | NULL 8 | -------------------------------------------------------------------------------- /R/rematch2.R: -------------------------------------------------------------------------------- 1 | re_match <- function(text, pattern, perl = TRUE, ...) { 2 | text <- as.character(text) 3 | 4 | match <- regexpr(pattern, text, perl = perl, ...) 5 | 6 | start <- as.vector(match) 7 | length <- attr(match, "match.length") 8 | end <- start + length - 1L 9 | 10 | matchstr <- substring(text, start, end) 11 | matchstr[start == -1] <- NA_character_ 12 | 13 | res <- data_frame(.text = text, .match = matchstr) 14 | 15 | if (!is.null(attr(match, "capture.start"))) { 16 | gstart <- attr(match, "capture.start") 17 | glength <- attr(match, "capture.length") 18 | gend <- gstart + glength - 1L 19 | 20 | groupstr <- substring(text, gstart, gend) 21 | groupstr[gstart == -1] <- NA_character_ 22 | dim(groupstr) <- dim(gstart) 23 | 24 | res <- cbind(groupstr, res, stringsAsFactors = FALSE) 25 | } 26 | names(res) <- c(attr(match, "capture.names"), ".text", ".match") 27 | class(res) <- c("tbl", class(res)) 28 | res 29 | } 30 | -------------------------------------------------------------------------------- /R/string.R: -------------------------------------------------------------------------------- 1 | #' Encode a `ps_handle` as a short string 2 | #' 3 | #' A convenient format for passing between processes, naming semaphores, or 4 | #' using as a directory/file name. Will always be 14 alphanumeric characters, 5 | #' with the first character guarantied to be a letter. Encodes the pid and 6 | #' creation time for a process. 7 | #' 8 | #' @param p Process handle. 9 | #' 10 | #' @return A process string (scalar character), that can be passed to 11 | #' `ps_handle()` in place of a pid. 12 | #' 13 | #' @export 14 | #' @examplesIf ps::ps_is_supported() && ! ps:::is_cran_check() 15 | #' (p <- ps_handle()) 16 | #' (str <- ps_string(p)) 17 | #' ps_handle(pid = str) 18 | 19 | ps_string <- function(p = ps_handle()) { 20 | assert_ps_handle(p) 21 | ps__str_encode(ps_pid(p), ps_create_time(p)) 22 | } 23 | 24 | 25 | ps__str_encode <- function(process_id, time) { 26 | whole_secs <- as.integer(time) 27 | micro_secs <- as.numeric(time) %% 1 * 1000000 28 | 29 | # Assumptions: 30 | # time between Jan 1st 1970 and Dec 5th 3769. 31 | # max time precision = 1/1,000,000 of a second. 32 | # pid <= 7,311,615 (current std max = 4,194,304). 33 | 34 | # Note: micro_secs has three extra unused bits 35 | 36 | map <- c(letters, LETTERS, 0:9) 37 | 38 | paste( 39 | collapse = '', 40 | map[ 41 | 1 + 42 | c( 43 | floor(process_id / 52^(3:0)) %% 52, 44 | floor(whole_secs / 62^(5:0)) %% 62, 45 | floor(micro_secs / 62^(3:0)) %% 62 46 | ) 47 | ] 48 | ) 49 | } 50 | 51 | 52 | ps__str_decode <- function(str) { 53 | map <- structure(0:61, names = c(letters, LETTERS, 0:9)) 54 | val <- map[strsplit(str, '', fixed = TRUE)[[1]]] 55 | 56 | process_id <- sum(val[01:04] * 52^(3:0)) 57 | whole_secs <- sum(val[05:10] * 62^(5:0)) 58 | micro_secs <- sum(val[11:14] * 62^(3:0)) 59 | 60 | time <- whole_secs + (micro_secs / 1000000) 61 | time <- as.POSIXct(time, tz = 'GMT', origin = '1970-01-01') 62 | 63 | # Allow fuzzy-matching the time by +/- 2 microseconds 64 | tryCatch( 65 | expr = { 66 | p <- ps_handle(pid = process_id) 67 | stopifnot(abs(ps_create_time(p) - time) < 2 / 1000000) 68 | p 69 | }, 70 | error = function(e) { 71 | ps_handle(pid = process_id, time = time) 72 | } 73 | ) 74 | } 75 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://ps.r-lib.org/ 2 | template: 3 | package: tidytemplate 4 | bootstrap: 5 5 | includes: 6 | in_header: | 7 | 8 | 9 | destination: docs 10 | 11 | development: 12 | mode: auto 13 | 14 | reference: 15 | - title: List processes 16 | contents: 17 | - ps 18 | - ps_apps 19 | - ps_pids 20 | 21 | - title: Process query API 22 | contents: 23 | - ps_children 24 | - ps_cmdline 25 | - ps_cpu_times 26 | - ps_create_time 27 | - ps_cwd 28 | - ps_descent 29 | - ps_environ 30 | - ps_exe 31 | - ps_handle 32 | - ps_is_running 33 | - ps_memory_info 34 | - ps_memory_full_info 35 | - ps_name 36 | - ps_num_threads 37 | - ps_pid 38 | - ps_ppid 39 | - ps_shared_libs 40 | - ps_status 41 | - ps_terminal 42 | - ps_uids 43 | - ps_username 44 | 45 | - title: Files and Network Connections 46 | contents: 47 | - ps_connections 48 | - ps_num_fds 49 | - ps_open_files 50 | 51 | - title: Process manipulation 52 | contents: 53 | - ps_interrupt 54 | - ps_kill 55 | - ps_resume 56 | - ps_send_signal 57 | - ps_suspend 58 | - ps_terminate 59 | - ps_get_cpu_affinity 60 | - ps_set_cpu_affinity 61 | - ps_get_nice 62 | - ps_set_nice 63 | - ps_wait 64 | - ps_windows_nice_values 65 | 66 | - title: Users 67 | contents: 68 | - ps_users 69 | 70 | - title: Disks and files 71 | contents: 72 | - ps_disk_partitions 73 | - ps_disk_usage 74 | - ps_disk_io_counters 75 | - ps_fs_info 76 | - ps_fs_mount_point 77 | - ps_fs_stat 78 | 79 | - title: Other system information 80 | contents: 81 | - ps_boot_time 82 | - ps_os_type 83 | - ps_cpu_count 84 | - ps_tty_size 85 | - ps_loadavg 86 | - ps_shared_lib_users 87 | - ps_system_cpu_times 88 | - ps_system_memory 89 | - ps_system_swap 90 | 91 | - title: Process tree cleanup 92 | contents: 93 | - ps_mark_tree 94 | - CleanupReporter 95 | 96 | - title: Utility functions 97 | contents: 98 | - ps_is_supported 99 | - ps_string 100 | - signals 101 | - errno 102 | -------------------------------------------------------------------------------- /air.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/ps/042d4836ac584c95a59985171fdfa3b6baf2fa6c/air.toml -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #' !/usr/bin/env sh 2 | 3 | rm -f src/Makevars src/config.h src/error-codes.c 4 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /configure.win: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env sh 2 | 3 | sh ./configure 4 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/ps/042d4836ac584c95a59985171fdfa3b6baf2fa6c/cran-comments.md -------------------------------------------------------------------------------- /header.md: -------------------------------------------------------------------------------- 1 | # ps 2 | 3 | > List, Query, Manipulate System Processes 4 | 5 | 6 | [![lifecycle](https://lifecycle.r-lib.org/articles/figures/lifecycle-stable.svg)](https://lifecycle.r-lib.org/articles/stages.html) 7 | [![R-CMD-check](https://github.com/r-lib/ps/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/ps/actions/workflows/R-CMD-check.yaml) 8 | [![CRAN status](https://www.r-pkg.org/badges/version/ps)](https://cran.r-project.org/package=ps) 9 | [![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/ps)](https://www.r-pkg.org/pkg/ps) 10 | [![Codecov test coverage](https://codecov.io/gh/r-lib/ps/graph/badge.svg)](https://app.codecov.io/gh/r-lib/ps) 11 | 12 | 13 | ps implements an API to query and manipulate system processes. Most of its 14 | code is based on the [psutil](https://github.com/giampaolo/psutil) Python 15 | package. 16 | 17 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | CTRL 2 | DRS 3 | IDEs 4 | macOS 5 | pageins 6 | pid 7 | Pid 8 | PID 9 | pids 10 | RStudio 11 | runnable 12 | SHR 13 | SIGCONT 14 | SIGKILL 15 | signalling 16 | testthat 17 | tibble 18 | TRS 19 | UDP 20 | uid 21 | unparsed 22 | VIRT 23 | -------------------------------------------------------------------------------- /inst/internals.md: -------------------------------------------------------------------------------- 1 | 2 | # `ps_handle` methods 3 | 4 | ``` 5 | method A C Z 6 | -------------- - - - 7 | ps_pid + . + 8 | ps_create_time + . + 9 | ps_is_running + . + 10 | ps_format + . + 11 | - 12 | ps_ppid . > + 13 | ps_parent . > + 14 | ps_name . > + 15 | ps_exe . > Z 16 | ps_cmdline . > Z 17 | ps_status . > + 18 | ps_username . > + 19 | ps_cwd . > Z 20 | ps_uids . > + 21 | ps_gids . > + 22 | ps_terminal . > + 23 | ps_environ . > Z 24 | ps_environ_raw . > Z 25 | ps_num_threads . > Z 26 | ps_cpu_times . > Z 27 | ps_memory_info . > Z 28 | ps_num_fds . > Z 29 | ps_open_files . > Z 30 | ps_connections . > Z 31 | ps_children . > + 32 | ps_send_signal . < + 33 | ps_suspend . < + 34 | ps_resume . < + 35 | ps_terminate . < + 36 | ps_kill . < + 37 | ps_interrupt . < + 38 | ``` 39 | 40 | ``` 41 | A: always works, even if the process has finished 42 | C: <: checks if process is running, before 43 | >: checks if process is running, after 44 | Z: +: works fine on a zombie 45 | Z: errors (zombie_process) on a zombie 46 | ``` 47 | 48 | # System API 49 | 50 | ## `ps()` 51 | 52 | ## `ps_pids()` 53 | 54 | ## `ps_boot_time()` 55 | 56 | ## Process cleanup 57 | 58 | `ps_kill_tree()`, `ps_mark_tree()`, `with_process_cleanup()`. 59 | 60 | ## `ps_os_type()` 61 | 62 | ## `signals()` 63 | -------------------------------------------------------------------------------- /inst/tools/winver.R: -------------------------------------------------------------------------------- 1 | winver_ver <- function(v = NULL) { 2 | if (is.null(v)) v <- system("cmd /c ver", intern = TRUE) 3 | v2 <- grep("\\[.*\\s.*\\]", v, value = TRUE)[1] 4 | v3 <- sub("^.*\\[[^ ]+\\s+", "", v2) 5 | v4 <- sub("\\]$", "", v3) 6 | if (is.na(v4)) stop("Failed to parse windows version") 7 | v4 8 | } 9 | 10 | winver_wmic <- function(v = NULL) { 11 | cmd <- "wmic os get Version /value" 12 | if (is.null(v)) v <- system(cmd, intern = TRUE) 13 | v2 <- grep("=", v, value = TRUE) 14 | v3 <- strsplit(v2, "=", fixed = TRUE)[[1]][2] 15 | v4 <- sub("\\s*$", "", sub("^\\s*", "", v3)) 16 | if (is.na(v4)) stop("Failed to parse windows version") 17 | v4 18 | } 19 | 20 | winver <- function() { 21 | ## First we try with `wmic` 22 | v <- if (Sys.which("wmic") != "") { 23 | tryCatch(winver_wmic(), error = function(e) NULL) 24 | } 25 | ## Otherwise `ver` 26 | if (is.null(v)) winver_ver() else v 27 | } 28 | 29 | if (is.null(sys.calls())) cat(winver()) 30 | -------------------------------------------------------------------------------- /man/CleanupReporter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/testthat-reporter.R 3 | \name{CleanupReporter} 4 | \alias{CleanupReporter} 5 | \title{testthat reporter that checks if child processes are cleaned up in tests} 6 | \usage{ 7 | CleanupReporter(reporter = testthat::ProgressReporter) 8 | } 9 | \arguments{ 10 | \item{reporter}{A testthat reporter to wrap into a new \code{CleanupReporter} 11 | class.} 12 | } 13 | \value{ 14 | New reporter class that behaves exactly like \code{reporter}, 15 | but it checks for, and optionally cleans up child processes, at the 16 | specified granularity. 17 | } 18 | \description{ 19 | \code{CleanupReporter} takes an existing testthat \code{Reporter} object, and 20 | wraps it, so it checks for leftover child processes, at the specified 21 | place, see the \code{proc_unit} argument below. 22 | } 23 | \details{ 24 | Child processes can be reported via a failed expectation, cleaned up 25 | silently, or cleaned up and reported (the default). 26 | 27 | If a \code{test_that()} block has an error, \code{CLeanupReporter} does not 28 | emit any expectations at the end of that block. The error will lead to a 29 | test failure anyway. It will still perform the cleanup, if requested, 30 | however. 31 | 32 | The constructor of the \code{CleanupReporter} class has options: 33 | \itemize{ 34 | \item \code{file}: the output file, if any, this is passed to \code{reporter}. 35 | \item \code{proc_unit}: when to perform the child process check and cleanup. 36 | Possible values: 37 | \itemize{ 38 | \item \code{"test"}: at the end of each \code{\link[testthat:test_that]{testthat::test_that()}} block 39 | (the default), 40 | \item \code{"testsuite"}: at the end of the test suite. 41 | } 42 | \item \code{proc_cleanup}: Logical scalar, whether to kill the leftover 43 | processes, \code{TRUE} by default. 44 | \item \code{proc_fail}: Whether to create an expectation, that fails if there 45 | are any processes alive, \code{TRUE} by default. 46 | \item \code{proc_timeout}: How long to wait for the processes to quit. This is 47 | sometimes needed, because even if some kill signals were sent to 48 | child processes, it might take a short time for these to take effect. 49 | It defaults to one second. 50 | \item \code{rconn_unit}: When to perform the R connection cleanup. Possible values 51 | are \code{"test"} and \code{"testsuite"}, like for \code{proc_unit}. 52 | \item \code{rconn_cleanup}: Logical scalar, whether to clean up leftover R 53 | connections. \code{TRUE} by default. 54 | \item \code{rconn_fail}: Whether to fail for leftover R connections. \code{TRUE} by 55 | default. 56 | \item \code{file_unit}: When to check for open files. Possible values are 57 | \code{"test"} and \code{"testsuite"}, like for \code{proc_unit}. 58 | \item \code{file_fail}: Whether to fail for leftover open files. \code{TRUE} by 59 | default. 60 | \item \code{conn_unit}: When to check for open network connections. 61 | Possible values are \code{"test"} and \code{"testsuite"}, like for \code{proc_unit}. 62 | \item \code{conn_fail}: Whether to fail for leftover network connections. 63 | \code{TRUE} by default. 64 | } 65 | } 66 | \note{ 67 | Some IDEs, like RStudio, start child processes frequently, and 68 | sometimes crash when these are killed, only use this reporter in a 69 | terminal session. In particular, you can always use it in the 70 | idiomatic \code{testthat.R} file, that calls \code{test_check()} during 71 | \verb{R CMD check}. 72 | } 73 | \section{Examples}{ 74 | 75 | This is how to use this reporter in \code{testthat.R}: 76 | 77 | \if{html}{\out{
}}\preformatted{library(testthat) 78 | library(mypackage) 79 | 80 | if (ps::ps_is_supported()) \{ 81 | reporter <- ps::CleanupReporter(testthat::ProgressReporter)$new( 82 | proc_unit = "test", proc_cleanup = TRUE) 83 | \} else \{ 84 | ## ps does not support this platform 85 | reporter <- "progress" 86 | \} 87 | 88 | test_check("mypackage", reporter = reporter) 89 | }\if{html}{\out{
}} 90 | } 91 | 92 | -------------------------------------------------------------------------------- /man/errno.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/errno.R 3 | \name{errno} 4 | \alias{errno} 5 | \title{List of 'errno' error codes} 6 | \usage{ 7 | errno() 8 | } 9 | \description{ 10 | For the errors that are not used on the current platform, \code{value} is 11 | \code{NA_integer_}. 12 | } 13 | \details{ 14 | A data frame with columns: \code{name}, \code{value}, \code{description}. 15 | } 16 | \examples{ 17 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 18 | errno() 19 | \dontshow{\}) # examplesIf} 20 | } 21 | -------------------------------------------------------------------------------- /man/ps-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ps-package.R 3 | \docType{package} 4 | \name{ps-package} 5 | \alias{ps-package} 6 | \title{ps: List, Query, Manipulate System Processes} 7 | \description{ 8 | List, query and manipulate all system processes, on 'Windows', 'Linux' and 'macOS'. 9 | } 10 | \seealso{ 11 | Useful links: 12 | \itemize{ 13 | \item \url{https://github.com/r-lib/ps} 14 | \item \url{https://ps.r-lib.org/} 15 | \item Report bugs at \url{https://github.com/r-lib/ps/issues} 16 | } 17 | 18 | } 19 | \author{ 20 | \strong{Maintainer}: Gábor Csárdi \email{csardi.gabor@gmail.com} 21 | 22 | Authors: 23 | \itemize{ 24 | \item Jay Loden 25 | \item Dave Daeschler 26 | \item Giampaolo Rodola' 27 | } 28 | 29 | Other contributors: 30 | \itemize{ 31 | \item Posit Software, PBC [copyright holder, funder] 32 | } 33 | 34 | } 35 | \keyword{internal} 36 | -------------------------------------------------------------------------------- /man/ps.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ps.R 3 | \name{ps} 4 | \alias{ps} 5 | \title{Process table} 6 | \usage{ 7 | ps(user = NULL, after = NULL, columns = NULL) 8 | } 9 | \arguments{ 10 | \item{user}{Username, to filter the results to matching processes.} 11 | 12 | \item{after}{Start time (\code{POSIXt}), to filter the results to processes 13 | that started after this.} 14 | 15 | \item{columns}{Columns to include in the result. If \code{NULL} (the default), 16 | then a default set of columns are returned, see below. The columns are 17 | shown in the same order they are specified in \code{columns}, but each 18 | column is included at most once. Use \code{"*"} to include all possible 19 | columns, and prefix a column name with \code{-} to remove it.} 20 | } 21 | \value{ 22 | Data frame, see columns below. 23 | } 24 | \description{ 25 | Data frame with the currently running processes. 26 | } 27 | \details{ 28 | Columns shown by default, if \code{columns} is not given or \code{NULL}: 29 | \itemize{ 30 | \item \code{pid}: Process ID. 31 | \item \code{ppid}: Process ID of parent process. 32 | \item \code{name}: Process name. 33 | \item \code{username}: Name of the user (real uid on POSIX). 34 | \item \code{status}: I.e. \emph{running}, \emph{sleeping}, etc. 35 | \item \code{user}: User CPU time. 36 | \item \code{system}: System CPU time. 37 | \item \code{rss}: Resident set size, the amount of memory the process currently 38 | uses. Does not include memory that is swapped out. It does include 39 | shared libraries. 40 | \item \code{vms}: Virtual memory size. All memory the process has access to. 41 | \item \code{created}: Time stamp when the process was created. 42 | \item \code{ps_handle}: \code{ps_handle} objects, in a list column. 43 | } 44 | 45 | Additional columns that can be requested via \code{columns}: 46 | \itemize{ 47 | \item \code{cmdline}: Command line, in a single string, from \code{\link[=ps_cmdline]{ps_cmdline()}}. 48 | \item \code{vcmdline}: Like \code{cmdline}, but each command line argument in a 49 | separate string. 50 | \item \code{cwd}: Current working directory, from \code{\link[=ps_cwd]{ps_cwd()}}. 51 | \item \code{exe}: Path of the executable of the process, from \code{\link[=ps_exe]{ps_exe()}}. 52 | \item \code{num_fds}: Number of open file descriptors, from \code{\link[=ps_num_fds]{ps_num_fds()}}. 53 | \item \code{num_threads}: Number of threads, from \code{\link[=ps_num_threads]{ps_num_threads()}}. 54 | \item \code{cpu_children_user}: See \code{\link[=ps_cpu_times]{ps_cpu_times()}}. 55 | \item \code{cpu_children_system}: See \code{\link[=ps_cpu_times]{ps_cpu_times()}}. 56 | \item \code{terminal}: Terminal device, from \code{\link[=ps_terminal]{ps_terminal()}}. 57 | \item \code{uid_real}: Real user id, from \code{\link[=ps_uids]{ps_uids()}}. 58 | \item \code{uid_effective}: Effective user id, from \code{\link[=ps_uids]{ps_uids()}}. 59 | \item \code{uid_saved}: Saved user id, from \code{\link[=ps_uids]{ps_uids()}}. 60 | \item \code{gid_real}: Real group id, from \code{\link[=ps_gids]{ps_gids()}}. 61 | \item \code{gid_effective}: Effective group id, from \code{\link[=ps_gids]{ps_gids()}}. 62 | \item \code{gid_saved}: Saved group id, from \code{\link[=ps_gids]{ps_gids()}}. 63 | \item \code{mem_shared}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 64 | \item \code{mem_text}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 65 | \item \code{mem_data}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 66 | \item \code{mem_lib}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 67 | \item \code{mem_dirty}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 68 | \item \code{mem_pfaults}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 69 | \item \code{mem_pageins}: See \code{\link[=ps_memory_info]{ps_memory_info()}}. 70 | \item \code{mem_maxrss}: See \code{\link[=ps_memory_full_info]{ps_memory_full_info()}}. 71 | \item \code{mem_uss}: See \code{\link[=ps_memory_full_info]{ps_memory_full_info()}}. 72 | \item \code{mem_pss}: See \code{\link[=ps_memory_full_info]{ps_memory_full_info()}}. 73 | \item \code{mem_swap}: See \code{\link[=ps_memory_full_info]{ps_memory_full_info()}}. 74 | } 75 | 76 | Use \code{"*"} in \code{columns} to include all columns. 77 | } 78 | -------------------------------------------------------------------------------- /man/ps_apps.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/macos.R 3 | \name{ps_apps} 4 | \alias{ps_apps} 5 | \title{List currently running applications} 6 | \usage{ 7 | ps_apps() 8 | } 9 | \value{ 10 | A data frame with columns: 11 | \itemize{ 12 | \item \code{pid}: integer process id. 13 | \item \code{name}: process name. 14 | \item \code{bundle_identifier}: bundle identifier, e.g. \code{com.apple.dock}. 15 | \item \code{bundle_url}: bundle URL, a \verb{file://} URL to the app bundle. 16 | \item \code{arch}: executable architecture, possible values are 17 | arm64, i386, x86_64, ppc, ppc64. 18 | \item \code{executable_url}: \verb{file://} URL to the executable file. 19 | \item \code{launch_date}: launch time stamp, a \code{POSIXct} object, may be \code{NA}. 20 | \item \code{finished_launching}: whether the app has finished launching. 21 | \item \code{active}: whether the app is active. 22 | \item \code{activation_policy}: one of the following values: 23 | \itemize{ 24 | \item \code{regular}: the application is an ordinary app that appears in the 25 | Dock and may have a user interface. 26 | \item \code{accessory}: the application doesn’t appear in the Dock and 27 | doesn’t have a menu bar, but it may be activated programmatically 28 | or by clicking on one of its windows. 29 | \item \code{prohibited}: the application doesn’t appear in the Dock and may 30 | not create windows or be activated. 31 | } 32 | } 33 | } 34 | \description{ 35 | This function currently only works on macOS. 36 | } 37 | \examples{ 38 | \dontshow{if (ps_is_supported() && ps_os_type()[["MACOS"]] && !ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 39 | ps_apps() 40 | \dontshow{\}) # examplesIf} 41 | } 42 | -------------------------------------------------------------------------------- /man/ps_boot_time.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_boot_time} 4 | \alias{ps_boot_time} 5 | \title{Boot time of the system} 6 | \usage{ 7 | ps_boot_time() 8 | } 9 | \value{ 10 | A \code{POSIXct} object. 11 | } 12 | \description{ 13 | Boot time of the system 14 | } 15 | -------------------------------------------------------------------------------- /man/ps_children.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_children} 4 | \alias{ps_children} 5 | \title{List of child processes (process objects) of the process. Note that 6 | this typically requires enumerating all processes on the system, so 7 | it is a costly operation.} 8 | \usage{ 9 | ps_children(p = ps_handle(), recursive = FALSE) 10 | } 11 | \arguments{ 12 | \item{p}{Process handle.} 13 | 14 | \item{recursive}{Whether to include the children of the children, etc.} 15 | } 16 | \value{ 17 | List of \code{ps_handle} objects. 18 | } 19 | \description{ 20 | List of child processes (process objects) of the process. Note that 21 | this typically requires enumerating all processes on the system, so 22 | it is a costly operation. 23 | } 24 | \examples{ 25 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 26 | p <- ps_parent(ps_handle()) 27 | ps_children(p) 28 | \dontshow{\}) # examplesIf} 29 | } 30 | \seealso{ 31 | Other process handle functions: 32 | \code{\link{ps_cmdline}()}, 33 | \code{\link{ps_connections}()}, 34 | \code{\link{ps_cpu_times}()}, 35 | \code{\link{ps_create_time}()}, 36 | \code{\link{ps_cwd}()}, 37 | \code{\link{ps_descent}()}, 38 | \code{\link{ps_environ}()}, 39 | \code{\link{ps_exe}()}, 40 | \code{\link{ps_handle}()}, 41 | \code{\link{ps_interrupt}()}, 42 | \code{\link{ps_is_running}()}, 43 | \code{\link{ps_kill}()}, 44 | \code{\link{ps_memory_info}()}, 45 | \code{\link{ps_name}()}, 46 | \code{\link{ps_num_fds}()}, 47 | \code{\link{ps_num_threads}()}, 48 | \code{\link{ps_open_files}()}, 49 | \code{\link{ps_pid}()}, 50 | \code{\link{ps_ppid}()}, 51 | \code{\link{ps_resume}()}, 52 | \code{\link{ps_send_signal}()}, 53 | \code{\link{ps_shared_libs}()}, 54 | \code{\link{ps_status}()}, 55 | \code{\link{ps_suspend}()}, 56 | \code{\link{ps_terminal}()}, 57 | \code{\link{ps_terminate}()}, 58 | \code{\link{ps_uids}()}, 59 | \code{\link{ps_username}()} 60 | } 61 | \concept{process handle functions} 62 | -------------------------------------------------------------------------------- /man/ps_cmdline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_cmdline} 4 | \alias{ps_cmdline} 5 | \title{Command line of the process} 6 | \usage{ 7 | ps_cmdline(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Character vector. 14 | } 15 | \description{ 16 | Command line of the process, i.e. the executable and the command line 17 | arguments, in a character vector. On Unix the program might change its 18 | command line, and some programs actually do it. 19 | } 20 | \details{ 21 | For a zombie process it throws a \code{zombie_process} error. 22 | } 23 | \examples{ 24 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 25 | p <- ps_handle() 26 | p 27 | ps_name(p) 28 | ps_exe(p) 29 | ps_cmdline(p) 30 | \dontshow{\}) # examplesIf} 31 | } 32 | \seealso{ 33 | Other process handle functions: 34 | \code{\link{ps_children}()}, 35 | \code{\link{ps_connections}()}, 36 | \code{\link{ps_cpu_times}()}, 37 | \code{\link{ps_create_time}()}, 38 | \code{\link{ps_cwd}()}, 39 | \code{\link{ps_descent}()}, 40 | \code{\link{ps_environ}()}, 41 | \code{\link{ps_exe}()}, 42 | \code{\link{ps_handle}()}, 43 | \code{\link{ps_interrupt}()}, 44 | \code{\link{ps_is_running}()}, 45 | \code{\link{ps_kill}()}, 46 | \code{\link{ps_memory_info}()}, 47 | \code{\link{ps_name}()}, 48 | \code{\link{ps_num_fds}()}, 49 | \code{\link{ps_num_threads}()}, 50 | \code{\link{ps_open_files}()}, 51 | \code{\link{ps_pid}()}, 52 | \code{\link{ps_ppid}()}, 53 | \code{\link{ps_resume}()}, 54 | \code{\link{ps_send_signal}()}, 55 | \code{\link{ps_shared_libs}()}, 56 | \code{\link{ps_status}()}, 57 | \code{\link{ps_suspend}()}, 58 | \code{\link{ps_terminal}()}, 59 | \code{\link{ps_terminate}()}, 60 | \code{\link{ps_uids}()}, 61 | \code{\link{ps_username}()} 62 | } 63 | \concept{process handle functions} 64 | -------------------------------------------------------------------------------- /man/ps_connections.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_connections} 4 | \alias{ps_connections} 5 | \title{List network connections of a process} 6 | \usage{ 7 | ps_connections(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Data frame, with columns: 14 | \itemize{ 15 | \item \code{fd}: integer file descriptor on POSIX systems, \code{NA} on Windows. 16 | \item \code{family}: Address family, string, typically \code{AF_UNIX}, \code{AF_INET} or 17 | \code{AF_INET6}. 18 | \item \code{type}: Socket type, string, typically \code{SOCK_STREAM} (TCP) or 19 | \code{SOCK_DGRAM} (UDP). 20 | \item \code{laddr}: Local address, string, \code{NA} for UNIX sockets. 21 | \item \code{lport}: Local port, integer, \code{NA} for UNIX sockets. 22 | \item \code{raddr}: Remote address, string, \code{NA} for UNIX sockets. This is 23 | always \code{NA} for \code{AF_INET} sockets on Linux. 24 | \item \code{rport}: Remote port, integer, \code{NA} for UNIX sockets. 25 | \item \code{state}: Socket state, e.g. \code{CONN_ESTABLISHED}, etc. It is \code{NA} 26 | for UNIX sockets. 27 | } 28 | } 29 | \description{ 30 | For a zombie process it throws a \code{zombie_process} error. 31 | } 32 | \examples{ 33 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 34 | p <- ps_handle() 35 | ps_connections(p) 36 | sc <- socketConnection("httpbin.org", port = 80) 37 | ps_connections(p) 38 | close(sc) 39 | ps_connections(p) 40 | \dontshow{\}) # examplesIf} 41 | } 42 | \seealso{ 43 | Other process handle functions: 44 | \code{\link{ps_children}()}, 45 | \code{\link{ps_cmdline}()}, 46 | \code{\link{ps_cpu_times}()}, 47 | \code{\link{ps_create_time}()}, 48 | \code{\link{ps_cwd}()}, 49 | \code{\link{ps_descent}()}, 50 | \code{\link{ps_environ}()}, 51 | \code{\link{ps_exe}()}, 52 | \code{\link{ps_handle}()}, 53 | \code{\link{ps_interrupt}()}, 54 | \code{\link{ps_is_running}()}, 55 | \code{\link{ps_kill}()}, 56 | \code{\link{ps_memory_info}()}, 57 | \code{\link{ps_name}()}, 58 | \code{\link{ps_num_fds}()}, 59 | \code{\link{ps_num_threads}()}, 60 | \code{\link{ps_open_files}()}, 61 | \code{\link{ps_pid}()}, 62 | \code{\link{ps_ppid}()}, 63 | \code{\link{ps_resume}()}, 64 | \code{\link{ps_send_signal}()}, 65 | \code{\link{ps_shared_libs}()}, 66 | \code{\link{ps_status}()}, 67 | \code{\link{ps_suspend}()}, 68 | \code{\link{ps_terminal}()}, 69 | \code{\link{ps_terminate}()}, 70 | \code{\link{ps_uids}()}, 71 | \code{\link{ps_username}()} 72 | } 73 | \concept{process handle functions} 74 | -------------------------------------------------------------------------------- /man/ps_cpu_count.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_cpu_count} 4 | \alias{ps_cpu_count} 5 | \title{Number of logical or physical CPUs} 6 | \usage{ 7 | ps_cpu_count(logical = TRUE) 8 | } 9 | \arguments{ 10 | \item{logical}{Whether to count logical CPUs.} 11 | } 12 | \value{ 13 | Integer scalar. 14 | } 15 | \description{ 16 | If cannot be determined, it returns \code{NA}. It also returns \code{NA} on older 17 | Windows systems, e.g. Vista or older and Windows Server 2008 or older. 18 | } 19 | \examples{ 20 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 21 | ps_cpu_count(logical = TRUE) 22 | ps_cpu_count(logical = FALSE) 23 | \dontshow{\}) # examplesIf} 24 | } 25 | -------------------------------------------------------------------------------- /man/ps_cpu_times.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_cpu_times} 4 | \alias{ps_cpu_times} 5 | \title{CPU times of the process} 6 | \usage{ 7 | ps_cpu_times(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Named real vector or length four: \code{user}, \code{system}, 14 | \code{children_user}, \code{children_system}. The last two are \code{NA} on 15 | non-Linux systems. 16 | } 17 | \description{ 18 | All times are measured in seconds: 19 | \itemize{ 20 | \item \code{user}: Amount of time that this process has been scheduled in user 21 | mode. 22 | \item \code{system}: Amount of time that this process has been scheduled in 23 | kernel mode 24 | \item \code{children_user}: On Linux, amount of time that this process's 25 | waited-for children have been scheduled in user mode. 26 | \item \code{children_system}: On Linux, Amount of time that this process's 27 | waited-for children have been scheduled in kernel mode. 28 | } 29 | } 30 | \details{ 31 | Throws a \code{zombie_process()} error for zombie processes. 32 | } 33 | \examples{ 34 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 35 | p <- ps_handle() 36 | p 37 | ps_cpu_times(p) 38 | proc.time() 39 | \dontshow{\}) # examplesIf} 40 | } 41 | \seealso{ 42 | Other process handle functions: 43 | \code{\link{ps_children}()}, 44 | \code{\link{ps_cmdline}()}, 45 | \code{\link{ps_connections}()}, 46 | \code{\link{ps_create_time}()}, 47 | \code{\link{ps_cwd}()}, 48 | \code{\link{ps_descent}()}, 49 | \code{\link{ps_environ}()}, 50 | \code{\link{ps_exe}()}, 51 | \code{\link{ps_handle}()}, 52 | \code{\link{ps_interrupt}()}, 53 | \code{\link{ps_is_running}()}, 54 | \code{\link{ps_kill}()}, 55 | \code{\link{ps_memory_info}()}, 56 | \code{\link{ps_name}()}, 57 | \code{\link{ps_num_fds}()}, 58 | \code{\link{ps_num_threads}()}, 59 | \code{\link{ps_open_files}()}, 60 | \code{\link{ps_pid}()}, 61 | \code{\link{ps_ppid}()}, 62 | \code{\link{ps_resume}()}, 63 | \code{\link{ps_send_signal}()}, 64 | \code{\link{ps_shared_libs}()}, 65 | \code{\link{ps_status}()}, 66 | \code{\link{ps_suspend}()}, 67 | \code{\link{ps_terminal}()}, 68 | \code{\link{ps_terminate}()}, 69 | \code{\link{ps_uids}()}, 70 | \code{\link{ps_username}()} 71 | } 72 | \concept{process handle functions} 73 | -------------------------------------------------------------------------------- /man/ps_create_time.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_create_time} 4 | \alias{ps_create_time} 5 | \title{Start time of a process} 6 | \usage{ 7 | ps_create_time(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | \code{POSIXct} object, start time, in GMT. 14 | } 15 | \description{ 16 | The pid and the start time pair serves as the identifier of the process, 17 | as process ids might be reused, but the chance of starting two processes 18 | with identical ids within the resolution of the timer is minimal. 19 | } 20 | \details{ 21 | This function works even if the process has already finished. 22 | } 23 | \examples{ 24 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 25 | p <- ps_handle() 26 | p 27 | ps_create_time(p) 28 | \dontshow{\}) # examplesIf} 29 | } 30 | \seealso{ 31 | Other process handle functions: 32 | \code{\link{ps_children}()}, 33 | \code{\link{ps_cmdline}()}, 34 | \code{\link{ps_connections}()}, 35 | \code{\link{ps_cpu_times}()}, 36 | \code{\link{ps_cwd}()}, 37 | \code{\link{ps_descent}()}, 38 | \code{\link{ps_environ}()}, 39 | \code{\link{ps_exe}()}, 40 | \code{\link{ps_handle}()}, 41 | \code{\link{ps_interrupt}()}, 42 | \code{\link{ps_is_running}()}, 43 | \code{\link{ps_kill}()}, 44 | \code{\link{ps_memory_info}()}, 45 | \code{\link{ps_name}()}, 46 | \code{\link{ps_num_fds}()}, 47 | \code{\link{ps_num_threads}()}, 48 | \code{\link{ps_open_files}()}, 49 | \code{\link{ps_pid}()}, 50 | \code{\link{ps_ppid}()}, 51 | \code{\link{ps_resume}()}, 52 | \code{\link{ps_send_signal}()}, 53 | \code{\link{ps_shared_libs}()}, 54 | \code{\link{ps_status}()}, 55 | \code{\link{ps_suspend}()}, 56 | \code{\link{ps_terminal}()}, 57 | \code{\link{ps_terminate}()}, 58 | \code{\link{ps_uids}()}, 59 | \code{\link{ps_username}()} 60 | } 61 | \concept{process handle functions} 62 | -------------------------------------------------------------------------------- /man/ps_cwd.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_cwd} 4 | \alias{ps_cwd} 5 | \title{Process current working directory as an absolute path.} 6 | \usage{ 7 | ps_cwd(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | String scalar. 14 | } 15 | \description{ 16 | For a zombie process it throws a \code{zombie_process} error. 17 | } 18 | \examples{ 19 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 20 | p <- ps_handle() 21 | p 22 | ps_cwd(p) 23 | \dontshow{\}) # examplesIf} 24 | } 25 | \seealso{ 26 | Other process handle functions: 27 | \code{\link{ps_children}()}, 28 | \code{\link{ps_cmdline}()}, 29 | \code{\link{ps_connections}()}, 30 | \code{\link{ps_cpu_times}()}, 31 | \code{\link{ps_create_time}()}, 32 | \code{\link{ps_descent}()}, 33 | \code{\link{ps_environ}()}, 34 | \code{\link{ps_exe}()}, 35 | \code{\link{ps_handle}()}, 36 | \code{\link{ps_interrupt}()}, 37 | \code{\link{ps_is_running}()}, 38 | \code{\link{ps_kill}()}, 39 | \code{\link{ps_memory_info}()}, 40 | \code{\link{ps_name}()}, 41 | \code{\link{ps_num_fds}()}, 42 | \code{\link{ps_num_threads}()}, 43 | \code{\link{ps_open_files}()}, 44 | \code{\link{ps_pid}()}, 45 | \code{\link{ps_ppid}()}, 46 | \code{\link{ps_resume}()}, 47 | \code{\link{ps_send_signal}()}, 48 | \code{\link{ps_shared_libs}()}, 49 | \code{\link{ps_status}()}, 50 | \code{\link{ps_suspend}()}, 51 | \code{\link{ps_terminal}()}, 52 | \code{\link{ps_terminate}()}, 53 | \code{\link{ps_uids}()}, 54 | \code{\link{ps_username}()} 55 | } 56 | \concept{process handle functions} 57 | -------------------------------------------------------------------------------- /man/ps_descent.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_descent} 4 | \alias{ps_descent} 5 | \title{Query the ancestry of a process} 6 | \usage{ 7 | ps_descent(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | A list of process handles, starting with \code{p}, each one 14 | is the parent process of the previous one. 15 | } 16 | \description{ 17 | Query the parent processes recursively, up to the first process. 18 | (On some platforms, like Windows, the process tree is not a tree 19 | and may contain loops, in which case \code{ps_descent()} only goes up 20 | until the first repetition.) 21 | } 22 | \examples{ 23 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 24 | ps_descent() 25 | \dontshow{\}) # examplesIf} 26 | } 27 | \seealso{ 28 | Other process handle functions: 29 | \code{\link{ps_children}()}, 30 | \code{\link{ps_cmdline}()}, 31 | \code{\link{ps_connections}()}, 32 | \code{\link{ps_cpu_times}()}, 33 | \code{\link{ps_create_time}()}, 34 | \code{\link{ps_cwd}()}, 35 | \code{\link{ps_environ}()}, 36 | \code{\link{ps_exe}()}, 37 | \code{\link{ps_handle}()}, 38 | \code{\link{ps_interrupt}()}, 39 | \code{\link{ps_is_running}()}, 40 | \code{\link{ps_kill}()}, 41 | \code{\link{ps_memory_info}()}, 42 | \code{\link{ps_name}()}, 43 | \code{\link{ps_num_fds}()}, 44 | \code{\link{ps_num_threads}()}, 45 | \code{\link{ps_open_files}()}, 46 | \code{\link{ps_pid}()}, 47 | \code{\link{ps_ppid}()}, 48 | \code{\link{ps_resume}()}, 49 | \code{\link{ps_send_signal}()}, 50 | \code{\link{ps_shared_libs}()}, 51 | \code{\link{ps_status}()}, 52 | \code{\link{ps_suspend}()}, 53 | \code{\link{ps_terminal}()}, 54 | \code{\link{ps_terminate}()}, 55 | \code{\link{ps_uids}()}, 56 | \code{\link{ps_username}()} 57 | } 58 | \concept{process handle functions} 59 | -------------------------------------------------------------------------------- /man/ps_disk_io_counters.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/disk.R 3 | \name{ps_disk_io_counters} 4 | \alias{ps_disk_io_counters} 5 | \title{System-wide disk I/O counters} 6 | \usage{ 7 | ps_disk_io_counters() 8 | } 9 | \value{ 10 | A data frame of one row per disk of I/O stats, with columns 11 | \code{name}, \code{read_count} \code{read_merged_count} \code{read_bytes}, \code{read_time}, 12 | \code{write_count}, \code{write_merged_count}, \code{write_bytes} \code{write_time}, and 13 | \code{busy_time}. 14 | } 15 | \description{ 16 | Returns a data.frame of system-wide disk I/O counters. 17 | } 18 | \details{ 19 | Includes the following non-NA fields for all supported platforms: 20 | \itemize{ 21 | \item \code{read_count}: number of reads 22 | \item \code{write_count}: number of writes 23 | \item \code{read_bytes}: number of bytes read 24 | \item \code{write_bytes}: number of bytes written 25 | } 26 | 27 | And for only some platforms: 28 | \itemize{ 29 | \item \code{read_time}: time spent reading from disk (in milliseconds) 30 | \item \code{write_time}: time spent writing to disk (in milliseconds) 31 | \item \code{busy_time}: time spent doing actual I/Os (in milliseconds) 32 | \item \code{read_merged_count}: number of merged reads (see iostats doc) 33 | \item \code{write_merged_count}: number of merged writes (see iostats doc) 34 | } 35 | } 36 | \examples{ 37 | \dontshow{if (ps::ps_is_supported() && ps:::ps_os_name() \%in\% c("LINUX", "WINDOWS") && !ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 38 | ps_disk_io_counters() 39 | \dontshow{\}) # examplesIf} 40 | } 41 | \seealso{ 42 | Other disk functions: 43 | \code{\link{ps_disk_partitions}()}, 44 | \code{\link{ps_disk_usage}()} 45 | } 46 | \concept{disk functions} 47 | -------------------------------------------------------------------------------- /man/ps_disk_partitions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/disk.R 3 | \name{ps_disk_partitions} 4 | \alias{ps_disk_partitions} 5 | \title{List all mounted partitions} 6 | \usage{ 7 | ps_disk_partitions(all = FALSE) 8 | } 9 | \arguments{ 10 | \item{all}{Whether to list virtual devices as well. If \code{FALSE}, on 11 | Linux it will still list \code{overlay} and \code{grpcfuse} file systems, to 12 | provide some useful information in Docker containers.} 13 | } 14 | \value{ 15 | A data frame with columns \code{device}, \code{mountpoint}, 16 | \code{fstype} and \code{options}. 17 | } 18 | \description{ 19 | The output is similar the Unix \code{mount} and \code{df} commands. 20 | } 21 | \examples{ 22 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 23 | ps_disk_partitions(all = TRUE) 24 | ps_disk_partitions() 25 | \dontshow{\}) # examplesIf} 26 | } 27 | \seealso{ 28 | Other disk functions: 29 | \code{\link{ps_disk_io_counters}()}, 30 | \code{\link{ps_disk_usage}()} 31 | } 32 | \concept{disk functions} 33 | -------------------------------------------------------------------------------- /man/ps_disk_usage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/disk.R 3 | \name{ps_disk_usage} 4 | \alias{ps_disk_usage} 5 | \title{Disk usage statistics, per partition} 6 | \usage{ 7 | ps_disk_usage(paths = ps_disk_partitions()$mountpoint) 8 | } 9 | \arguments{ 10 | \item{paths}{The mounted file systems to list. By default all file 11 | systems returned by \code{\link[=ps_disk_partitions]{ps_disk_partitions()}} is listed.} 12 | } 13 | \value{ 14 | A data frame with columns \code{mountpoint}, \code{total}, \code{used}, 15 | \code{available} and \code{capacity}. 16 | } 17 | \description{ 18 | The output is similar to the Unix \code{df} command. 19 | } 20 | \details{ 21 | Note that on Unix a small percentage of the disk space (5\% typically) 22 | is reserved for the superuser. \code{ps_disk_usage()} returns the space 23 | available to the calling user. 24 | } 25 | \examples{ 26 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 27 | ps_disk_usage() 28 | \dontshow{\}) # examplesIf} 29 | } 30 | \seealso{ 31 | Other disk functions: 32 | \code{\link{ps_disk_io_counters}()}, 33 | \code{\link{ps_disk_partitions}()} 34 | } 35 | \concept{disk functions} 36 | -------------------------------------------------------------------------------- /man/ps_environ.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_environ} 4 | \alias{ps_environ} 5 | \alias{ps_environ_raw} 6 | \title{Environment variables of a process} 7 | \usage{ 8 | ps_environ(p = ps_handle()) 9 | 10 | ps_environ_raw(p = ps_handle()) 11 | } 12 | \arguments{ 13 | \item{p}{Process handle.} 14 | } 15 | \value{ 16 | \code{ps_environ()} returns a named character vector (that has a 17 | \code{Dlist} class, so it is printed nicely), \code{ps_environ_raw()} returns a 18 | character vector. 19 | } 20 | \description{ 21 | \code{ps_environ()} returns the environment variables of the process, in a 22 | named vector, similarly to the return value of \code{Sys.getenv()} 23 | (without arguments). 24 | } 25 | \details{ 26 | Note: this usually does not reflect changes made after the process 27 | started. 28 | 29 | \code{ps_environ_raw()} is similar to \code{p$environ()} but returns the 30 | unparsed \code{"var=value"} strings. This is faster, and sometimes good 31 | enough. 32 | 33 | These functions throw a \code{zombie_process} error for zombie processes. 34 | } 35 | \section{macOS issues}{ 36 | 37 | 38 | \code{ps_environ()} usually does not work on macOS nowadays. This is because 39 | macOS does not allow reading the environment variables of another 40 | process. Accoding to the Darwin source code, \code{ps_environ} will work is 41 | one of these conditions hold: 42 | \itemize{ 43 | \item You are running a development or debug kernel, i.e. if you are 44 | debugging the macOS kernel itself. 45 | \item The target process is same as the calling process. 46 | \item SIP if off. 47 | \item The target process is not restricted, e.g. it is running a binary 48 | that was not signed. 49 | \item The calling process has the 50 | \code{com.apple.private.read-environment-variables} entitlement. However 51 | adding this entitlement to the R binary makes R crash on startup. 52 | } 53 | 54 | Otherwise \code{ps_environ} will return an empty set of environment variables 55 | on macOS. 56 | 57 | Issue 121 might have more information about this. 58 | } 59 | 60 | \examples{ 61 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 62 | p <- ps_handle() 63 | p 64 | env <- ps_environ(p) 65 | env[["R_HOME"]] 66 | \dontshow{\}) # examplesIf} 67 | } 68 | \seealso{ 69 | Other process handle functions: 70 | \code{\link{ps_children}()}, 71 | \code{\link{ps_cmdline}()}, 72 | \code{\link{ps_connections}()}, 73 | \code{\link{ps_cpu_times}()}, 74 | \code{\link{ps_create_time}()}, 75 | \code{\link{ps_cwd}()}, 76 | \code{\link{ps_descent}()}, 77 | \code{\link{ps_exe}()}, 78 | \code{\link{ps_handle}()}, 79 | \code{\link{ps_interrupt}()}, 80 | \code{\link{ps_is_running}()}, 81 | \code{\link{ps_kill}()}, 82 | \code{\link{ps_memory_info}()}, 83 | \code{\link{ps_name}()}, 84 | \code{\link{ps_num_fds}()}, 85 | \code{\link{ps_num_threads}()}, 86 | \code{\link{ps_open_files}()}, 87 | \code{\link{ps_pid}()}, 88 | \code{\link{ps_ppid}()}, 89 | \code{\link{ps_resume}()}, 90 | \code{\link{ps_send_signal}()}, 91 | \code{\link{ps_shared_libs}()}, 92 | \code{\link{ps_status}()}, 93 | \code{\link{ps_suspend}()}, 94 | \code{\link{ps_terminal}()}, 95 | \code{\link{ps_terminate}()}, 96 | \code{\link{ps_uids}()}, 97 | \code{\link{ps_username}()} 98 | } 99 | \concept{process handle functions} 100 | -------------------------------------------------------------------------------- /man/ps_exe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_exe} 4 | \alias{ps_exe} 5 | \title{Full path of the executable of a process} 6 | \usage{ 7 | ps_exe(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Character scalar. 14 | } 15 | \description{ 16 | Path to the executable of the process. May also be an empty string or 17 | \code{NA} if it cannot be determined. 18 | } 19 | \details{ 20 | For a zombie process it throws a \code{zombie_process} error. 21 | } 22 | \examples{ 23 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 24 | p <- ps_handle() 25 | p 26 | ps_name(p) 27 | ps_exe(p) 28 | ps_cmdline(p) 29 | \dontshow{\}) # examplesIf} 30 | } 31 | \seealso{ 32 | Other process handle functions: 33 | \code{\link{ps_children}()}, 34 | \code{\link{ps_cmdline}()}, 35 | \code{\link{ps_connections}()}, 36 | \code{\link{ps_cpu_times}()}, 37 | \code{\link{ps_create_time}()}, 38 | \code{\link{ps_cwd}()}, 39 | \code{\link{ps_descent}()}, 40 | \code{\link{ps_environ}()}, 41 | \code{\link{ps_handle}()}, 42 | \code{\link{ps_interrupt}()}, 43 | \code{\link{ps_is_running}()}, 44 | \code{\link{ps_kill}()}, 45 | \code{\link{ps_memory_info}()}, 46 | \code{\link{ps_name}()}, 47 | \code{\link{ps_num_fds}()}, 48 | \code{\link{ps_num_threads}()}, 49 | \code{\link{ps_open_files}()}, 50 | \code{\link{ps_pid}()}, 51 | \code{\link{ps_ppid}()}, 52 | \code{\link{ps_resume}()}, 53 | \code{\link{ps_send_signal}()}, 54 | \code{\link{ps_shared_libs}()}, 55 | \code{\link{ps_status}()}, 56 | \code{\link{ps_suspend}()}, 57 | \code{\link{ps_terminal}()}, 58 | \code{\link{ps_terminate}()}, 59 | \code{\link{ps_uids}()}, 60 | \code{\link{ps_username}()} 61 | } 62 | \concept{process handle functions} 63 | -------------------------------------------------------------------------------- /man/ps_fs_mount_point.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/disk.R 3 | \name{ps_fs_mount_point} 4 | \alias{ps_fs_mount_point} 5 | \title{Find the mount point of a file or directory} 6 | \usage{ 7 | ps_fs_mount_point(paths) 8 | } 9 | \arguments{ 10 | \item{paths}{Paths to files, directories, devices, etc. They must 11 | exist. They are normalized using \code{\link[base:normalizePath]{base::normalizePath()}}.} 12 | } 13 | \value{ 14 | Character vector, paths to the mount points of the input 15 | \code{paths}. 16 | } 17 | \description{ 18 | Find the mount point of a file or directory 19 | } 20 | \examples{ 21 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 22 | ps_fs_mount_point(".") 23 | \dontshow{\}) # examplesIf} 24 | } 25 | -------------------------------------------------------------------------------- /man/ps_fs_stat.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/disk.R 3 | \name{ps_fs_stat} 4 | \alias{ps_fs_stat} 5 | \title{File status} 6 | \usage{ 7 | ps_fs_stat(paths, follow = TRUE) 8 | } 9 | \arguments{ 10 | \item{paths}{Paths to files, directories, devices, etc. They must 11 | exist. They are expanded using \code{\link[base:path.expand]{base::path.expand()}}.} 12 | 13 | \item{follow}{Whether to follow symbolic links. If \code{FALSE} it returns 14 | information on the links themselves.} 15 | } 16 | \value{ 17 | Data frame with one row for each path in \code{paths}. Columns: 18 | \itemize{ 19 | \item \code{path}: Expanded \code{paths}. 20 | \item \code{dev_major}: Major device ID of the device the path resides on. 21 | \item \code{dev_minor}: Minor device ID of the device the path resodes on. 22 | \item \code{inode}: Inode number. 23 | \item \code{mode}: File type and mode (permissions). It is easier to use the 24 | \code{type} and \code{permissions} columns. 25 | \item \code{type}: File type, character. One of 26 | regular file, directory, character device, block device, FIFO, symbolic link, socket. 27 | \item \code{permissions}: Permissions, numeric code in an integer column. 28 | \item \code{nlink}: Number of hard links. 29 | \item \code{uid}: User id of owner. 30 | \item \code{gid}: Group id of owner. 31 | \item \code{rdev_major}: If the path is a device, its major device id, 32 | otherwise \code{NA_integer_}. 33 | \item \code{rdev_minor}: IF the path is a device, its minor device id, 34 | otherwise \code{NA_integer_}. 35 | \item \code{size}: File size in bytes. 36 | \item \code{block_size}: Block size for filesystem I/O. 37 | \item \code{blocks}: Number of 512B blocks allocated. 38 | \item \code{access_time}: Time of last access. 39 | \item \code{modification_time}: Time of last modification. 40 | \item \code{change_time}: Time of last status change. 41 | } 42 | } 43 | \description{ 44 | This function is currently not implemented on Windows. 45 | } 46 | \examples{ 47 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check() && ps_os_type()[["POSIX"]]) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 48 | ps_fs_stat(c(".", tempdir())) 49 | \dontshow{\}) # examplesIf} 50 | } 51 | -------------------------------------------------------------------------------- /man/ps_get_cpu_affinity.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_get_cpu_affinity} 4 | \alias{ps_get_cpu_affinity} 5 | \alias{ps_set_cpu_affinity} 6 | \title{Query or set CPU affinity} 7 | \usage{ 8 | ps_get_cpu_affinity(p = ps_handle()) 9 | 10 | ps_set_cpu_affinity(p = ps_handle(), affinity) 11 | } 12 | \arguments{ 13 | \item{p}{Process handle.} 14 | 15 | \item{affinity}{Integer vector of CPU numbers to restrict a process to. 16 | CPU numbers start with zero, and they have to be smaller than the 17 | number of (logical) CPUs, see \code{\link[=ps_cpu_count]{ps_cpu_count()}}.} 18 | } 19 | \value{ 20 | \code{ps_get_cpu_affinity()} returns an integer vector of CPU 21 | numbers, starting with zero. 22 | 23 | \code{ps_set_cpu_affinity()} returns \code{NULL}, invisibly. 24 | } 25 | \description{ 26 | \code{ps_get_cpu_affinity()} queries the 27 | \href{https://www.linuxjournal.com/article/6799?page=0,0}{CPU affinity} of 28 | a process. \code{ps_set_cpu_affinity()} sets the CPU affinity of a process. 29 | } 30 | \details{ 31 | CPU affinity consists in telling the OS to run a process on a limited 32 | set of CPUs only (on Linux cmdline, the \code{taskset} command is typically 33 | used). 34 | 35 | These functions are only supported on Linux and Windows. They error on macOS. 36 | } 37 | \examples{ 38 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check() && ! ps::ps_os_type()[["MACOS"]]) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 39 | # current 40 | orig <- ps_get_cpu_affinity() 41 | orig 42 | 43 | # restrict 44 | ps_set_cpu_affinity(affinity = 0:0) 45 | ps_get_cpu_affinity() 46 | 47 | # restore 48 | ps_set_cpu_affinity(affinity = orig) 49 | ps_get_cpu_affinity() 50 | \dontshow{\}) # examplesIf} 51 | } 52 | -------------------------------------------------------------------------------- /man/ps_get_nice.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_windows_nice_values} 4 | \alias{ps_windows_nice_values} 5 | \alias{ps_get_nice} 6 | \alias{ps_set_nice} 7 | \title{Get or set the priority of a process} 8 | \usage{ 9 | ps_windows_nice_values() 10 | 11 | ps_get_nice(p = ps_handle()) 12 | 13 | ps_set_nice(p = ps_handle(), value) 14 | } 15 | \arguments{ 16 | \item{p}{Process handle.} 17 | 18 | \item{value}{On Windows it must be a string, one of the values of 19 | \code{ps_windows_nice_values()}. On Unix it is a priority value that is 20 | smaller than or equal to 20.} 21 | } 22 | \value{ 23 | \code{ps_windows_nice_values()} return a character vector of possible 24 | priority values on Windows. 25 | 26 | \code{ps_get_nice()} returns a string from 27 | \code{ps_windows_nice_values()} on Windows. On Unix it returns an integer 28 | smaller than or equal to 20. 29 | 30 | \code{ps_set_nice()} return \code{NULL} invisibly. 31 | } 32 | \description{ 33 | \code{ps_get_nice()} returns the current priority, \code{ps_set_nice()} sets a 34 | new priority, \code{ps_windows_nice_values()} list the possible priority 35 | values on Windows. 36 | } 37 | \details{ 38 | Priority values are different on Windows and Unix. 39 | 40 | On Unix, priority is an integer, which is maximum 20. 20 is the lowest 41 | priority. 42 | \subsection{Rules:}{ 43 | \itemize{ 44 | \item On Windows you can only set the priority of the processes the current 45 | user has \code{PROCESS_SET_INFORMATION} access rights to. This typically 46 | means your own processes. 47 | \item On Unix you can only set the priority of the your own processes. 48 | The superuser can set the priority of any process. 49 | \item On Unix you cannot set a higher priority, unless you are the superuser. 50 | (I.e. you cannot set a lower number.) 51 | \item On Unix the default priority of a process is zero. 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /man/ps_handle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_handle} 4 | \alias{ps_handle} 5 | \alias{as.character.ps_handle} 6 | \alias{format.ps_handle} 7 | \alias{print.ps_handle} 8 | \title{Create a process handle} 9 | \usage{ 10 | ps_handle(pid = NULL, time = NULL) 11 | 12 | \method{as.character}{ps_handle}(x, ...) 13 | 14 | \method{format}{ps_handle}(x, ...) 15 | 16 | \method{print}{ps_handle}(x, ...) 17 | } 18 | \arguments{ 19 | \item{pid}{A process id (integer scalar) or process string (from 20 | \code{ps_string()}). \code{NULL} means the current R process.} 21 | 22 | \item{time}{Start time of the process. Usually \code{NULL} and ps will query 23 | the start time.} 24 | 25 | \item{x}{Process handle.} 26 | 27 | \item{...}{Not used currently.} 28 | } 29 | \value{ 30 | \code{ps_handle()} returns a process handle (class \code{ps_handle}). 31 | } 32 | \description{ 33 | Create a process handle 34 | } 35 | \examples{ 36 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 37 | p <- ps_handle() 38 | p 39 | \dontshow{\}) # examplesIf} 40 | } 41 | \seealso{ 42 | Other process handle functions: 43 | \code{\link{ps_children}()}, 44 | \code{\link{ps_cmdline}()}, 45 | \code{\link{ps_connections}()}, 46 | \code{\link{ps_cpu_times}()}, 47 | \code{\link{ps_create_time}()}, 48 | \code{\link{ps_cwd}()}, 49 | \code{\link{ps_descent}()}, 50 | \code{\link{ps_environ}()}, 51 | \code{\link{ps_exe}()}, 52 | \code{\link{ps_interrupt}()}, 53 | \code{\link{ps_is_running}()}, 54 | \code{\link{ps_kill}()}, 55 | \code{\link{ps_memory_info}()}, 56 | \code{\link{ps_name}()}, 57 | \code{\link{ps_num_fds}()}, 58 | \code{\link{ps_num_threads}()}, 59 | \code{\link{ps_open_files}()}, 60 | \code{\link{ps_pid}()}, 61 | \code{\link{ps_ppid}()}, 62 | \code{\link{ps_resume}()}, 63 | \code{\link{ps_send_signal}()}, 64 | \code{\link{ps_shared_libs}()}, 65 | \code{\link{ps_status}()}, 66 | \code{\link{ps_suspend}()}, 67 | \code{\link{ps_terminal}()}, 68 | \code{\link{ps_terminate}()}, 69 | \code{\link{ps_uids}()}, 70 | \code{\link{ps_username}()} 71 | } 72 | \concept{process handle functions} 73 | -------------------------------------------------------------------------------- /man/ps_interrupt.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_interrupt} 4 | \alias{ps_interrupt} 5 | \title{Interrupt a process} 6 | \usage{ 7 | ps_interrupt(p = ps_handle(), ctrl_c = TRUE) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle or a list of process handles.} 11 | 12 | \item{ctrl_c}{On Windows, whether to send 'CTRL+C'. If \code{FALSE}, then 13 | 'CTRL+BREAK' is sent. Ignored on non-Windows platforms.} 14 | } 15 | \description{ 16 | Sends \code{SIGINT} on POSIX, and 'CTRL+C' or 'CTRL+BREAK' on Windows. 17 | } 18 | \seealso{ 19 | Other process handle functions: 20 | \code{\link{ps_children}()}, 21 | \code{\link{ps_cmdline}()}, 22 | \code{\link{ps_connections}()}, 23 | \code{\link{ps_cpu_times}()}, 24 | \code{\link{ps_create_time}()}, 25 | \code{\link{ps_cwd}()}, 26 | \code{\link{ps_descent}()}, 27 | \code{\link{ps_environ}()}, 28 | \code{\link{ps_exe}()}, 29 | \code{\link{ps_handle}()}, 30 | \code{\link{ps_is_running}()}, 31 | \code{\link{ps_kill}()}, 32 | \code{\link{ps_memory_info}()}, 33 | \code{\link{ps_name}()}, 34 | \code{\link{ps_num_fds}()}, 35 | \code{\link{ps_num_threads}()}, 36 | \code{\link{ps_open_files}()}, 37 | \code{\link{ps_pid}()}, 38 | \code{\link{ps_ppid}()}, 39 | \code{\link{ps_resume}()}, 40 | \code{\link{ps_send_signal}()}, 41 | \code{\link{ps_shared_libs}()}, 42 | \code{\link{ps_status}()}, 43 | \code{\link{ps_suspend}()}, 44 | \code{\link{ps_terminal}()}, 45 | \code{\link{ps_terminate}()}, 46 | \code{\link{ps_uids}()}, 47 | \code{\link{ps_username}()} 48 | } 49 | \concept{process handle functions} 50 | -------------------------------------------------------------------------------- /man/ps_is_running.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_is_running} 4 | \alias{ps_is_running} 5 | \title{Checks whether a process is running} 6 | \usage{ 7 | ps_is_running(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Logical scalar. 14 | } 15 | \description{ 16 | It returns \code{FALSE} if the process has already finished. 17 | } 18 | \details{ 19 | It uses the start time of the process to work around pid reuse. I.e. 20 | } 21 | \examples{ 22 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 23 | p <- ps_handle() 24 | p 25 | ps_is_running(p) 26 | \dontshow{\}) # examplesIf} 27 | } 28 | \seealso{ 29 | Other process handle functions: 30 | \code{\link{ps_children}()}, 31 | \code{\link{ps_cmdline}()}, 32 | \code{\link{ps_connections}()}, 33 | \code{\link{ps_cpu_times}()}, 34 | \code{\link{ps_create_time}()}, 35 | \code{\link{ps_cwd}()}, 36 | \code{\link{ps_descent}()}, 37 | \code{\link{ps_environ}()}, 38 | \code{\link{ps_exe}()}, 39 | \code{\link{ps_handle}()}, 40 | \code{\link{ps_interrupt}()}, 41 | \code{\link{ps_kill}()}, 42 | \code{\link{ps_memory_info}()}, 43 | \code{\link{ps_name}()}, 44 | \code{\link{ps_num_fds}()}, 45 | \code{\link{ps_num_threads}()}, 46 | \code{\link{ps_open_files}()}, 47 | \code{\link{ps_pid}()}, 48 | \code{\link{ps_ppid}()}, 49 | \code{\link{ps_resume}()}, 50 | \code{\link{ps_send_signal}()}, 51 | \code{\link{ps_shared_libs}()}, 52 | \code{\link{ps_status}()}, 53 | \code{\link{ps_suspend}()}, 54 | \code{\link{ps_terminal}()}, 55 | \code{\link{ps_terminate}()}, 56 | \code{\link{ps_uids}()}, 57 | \code{\link{ps_username}()} 58 | } 59 | \concept{process handle functions} 60 | -------------------------------------------------------------------------------- /man/ps_kill.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_kill} 4 | \alias{ps_kill} 5 | \title{Kill one or more processes} 6 | \usage{ 7 | ps_kill(p = ps_handle(), grace = 200) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle, or a list of process handles.} 11 | 12 | \item{grace}{Grace period, in milliseconds, used on Unix. If it is not 13 | zero, then \code{ps_kill()} first sends a \code{SIGTERM} signal to all processes 14 | in \code{p}. If some proccesses do not terminate within \code{grace} 15 | milliseconds after the \code{SIGTERM} signal, \code{ps_kill()} kills them by 16 | sending \code{SIGKILL} signals.} 17 | } 18 | \value{ 19 | Character vector, with one element for each process handle in 20 | \code{p}. If the process was already dead before \code{ps_kill()} tried to kill 21 | it, the corresponding return value is \code{"dead"}. If \code{ps_kill()} just 22 | killed it, it is \code{"killed"}. 23 | } 24 | \description{ 25 | Kill the process with SIGKILL preemptively checking whether PID has 26 | been reused. On Windows it uses \code{TerminateProcess()}. 27 | } 28 | \details{ 29 | Note that since ps version 1.8, \code{ps_kill()} does not error if the 30 | \code{p} process (or some processes if \code{p} is a list) are already terminated. 31 | } 32 | \examples{ 33 | \dontshow{if (ps::ps_is_supported() && ps::ps_os_type()["POSIX"] && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 34 | px <- processx::process$new("sleep", "10") 35 | p <- ps_handle(px$get_pid()) 36 | p 37 | ps_kill(p) 38 | p 39 | ps_is_running(p) 40 | px$get_exit_status() 41 | \dontshow{\}) # examplesIf} 42 | } 43 | \seealso{ 44 | Other process handle functions: 45 | \code{\link{ps_children}()}, 46 | \code{\link{ps_cmdline}()}, 47 | \code{\link{ps_connections}()}, 48 | \code{\link{ps_cpu_times}()}, 49 | \code{\link{ps_create_time}()}, 50 | \code{\link{ps_cwd}()}, 51 | \code{\link{ps_descent}()}, 52 | \code{\link{ps_environ}()}, 53 | \code{\link{ps_exe}()}, 54 | \code{\link{ps_handle}()}, 55 | \code{\link{ps_interrupt}()}, 56 | \code{\link{ps_is_running}()}, 57 | \code{\link{ps_memory_info}()}, 58 | \code{\link{ps_name}()}, 59 | \code{\link{ps_num_fds}()}, 60 | \code{\link{ps_num_threads}()}, 61 | \code{\link{ps_open_files}()}, 62 | \code{\link{ps_pid}()}, 63 | \code{\link{ps_ppid}()}, 64 | \code{\link{ps_resume}()}, 65 | \code{\link{ps_send_signal}()}, 66 | \code{\link{ps_shared_libs}()}, 67 | \code{\link{ps_status}()}, 68 | \code{\link{ps_suspend}()}, 69 | \code{\link{ps_terminal}()}, 70 | \code{\link{ps_terminate}()}, 71 | \code{\link{ps_uids}()}, 72 | \code{\link{ps_username}()} 73 | } 74 | \concept{process handle functions} 75 | -------------------------------------------------------------------------------- /man/ps_kill_tree.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/kill-tree.R 3 | \name{ps_mark_tree} 4 | \alias{ps_mark_tree} 5 | \alias{with_process_cleanup} 6 | \alias{ps_find_tree} 7 | \alias{ps_kill_tree} 8 | \title{Mark a process and its (future) child tree} 9 | \usage{ 10 | ps_mark_tree() 11 | 12 | with_process_cleanup(expr) 13 | 14 | ps_find_tree(marker) 15 | 16 | ps_kill_tree(marker, sig = signals()$SIGKILL, grace = 200) 17 | } 18 | \arguments{ 19 | \item{expr}{R expression to evaluate in the new context.} 20 | 21 | \item{marker}{String scalar, the name of the environment variable to 22 | use to find the marked processes.} 23 | 24 | \item{sig}{The signal to send to the marked processes on Unix. On 25 | Windows this argument is ignored currently.} 26 | 27 | \item{grace}{Grace period, in milliseconds, used on Unix, if \code{sig} is 28 | \code{SIGKILL}. If it is not zero, then \code{ps_kill_tree()} first sends a 29 | \code{SIGTERM} signal to all processes. If some proccesses do not 30 | terminate within \code{grace} milliseconds after the \code{SIGTERM} signal, 31 | \code{ps_kill_tree()} kills them by sending \code{SIGKILL} signals.} 32 | } 33 | \value{ 34 | \code{ps_mark_tree()} returns the name of the environment variable, 35 | which can be used as the \code{marker} in \code{ps_kill_tree()}. 36 | 37 | \code{ps_find_tree()} returns a list of \code{ps_handle} objects. 38 | 39 | \code{ps_kill_tree()} returns the pids of the killed processes, in a named 40 | integer vector. The names are the file names of the executables, when 41 | available. 42 | 43 | \code{with_process_cleanup()} returns the value of the evaluated expression. 44 | } 45 | \description{ 46 | \code{ps_mark_tree()} generates a random environment variable name and sets 47 | it in the current R process. This environment variable will be (by 48 | default) inherited by all child (and grandchild, etc.) processes, and 49 | will help finding these processes, even if and when they are (no longer) 50 | related to the current R process. (I.e. they are not connected in the 51 | process tree.) 52 | } 53 | \details{ 54 | \code{ps_find_tree()} finds the processes that set the supplied environment 55 | variable and returns them in a list. 56 | 57 | \code{ps_kill_tree()} finds the processes that set the supplied environment 58 | variable, and kills them (or sends them the specified signal on Unix). 59 | 60 | \code{with_process_cleanup()} evaluates an R expression, and cleans up all 61 | external processes that were started by the R process while evaluating 62 | the expression. This includes child processes of child processes, etc., 63 | recursively. It returns a list with entries: \code{result} is the result of 64 | the expression, \code{visible} is TRUE if the expression should be printed 65 | to the screen, and \code{process_cleanup} is a named integer vector of the 66 | cleaned pids, names are the process names. 67 | 68 | If \code{expr} throws an error, then so does \code{with_process_cleanup()}, the 69 | same error. Nevertheless processes are still cleaned up. 70 | } 71 | \section{macOS issues}{ 72 | 73 | 74 | These functions do not work on macOS, unless specific criteria are 75 | met. See \code{\link[=ps_environ]{ps_environ()}} for details. 76 | } 77 | 78 | \section{Note}{ 79 | 80 | Note that \code{with_process_cleanup()} is problematic if the R process is 81 | multi-threaded and the other threads start subprocesses. 82 | \code{with_process_cleanup()} cleans up those processes as well, which is 83 | probably not what you want. This is an issue for example in RStudio. 84 | Do not use \code{with_process_cleanup()}, unless you are sure that the 85 | R process is single-threaded, or the other threads do not start 86 | subprocesses. E.g. using it in package test cases is usually fine, 87 | because RStudio runs these in a separate single-threaded process. 88 | 89 | The same holds for manually running \code{ps_mark_tree()} and then 90 | \code{ps_find_tree()} or \code{ps_kill_tree()}. 91 | 92 | A safe way to use process cleanup is to use the processx package to 93 | start subprocesses, and set the \code{cleanup_tree = TRUE} in 94 | \code{\link[processx:run]{processx::run()}} or the \link[processx:process]{processx::process} constructor. 95 | } 96 | 97 | -------------------------------------------------------------------------------- /man/ps_loadavg.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_loadavg} 4 | \alias{ps_loadavg} 5 | \title{Return the average system load over the last 1, 5 and 15 minutes as a 6 | tuple.} 7 | \usage{ 8 | ps_loadavg() 9 | } 10 | \value{ 11 | Numeric vector of length 3. 12 | } 13 | \description{ 14 | The “load” represents the processes which are in a runnable 15 | state, either using the CPU or waiting to use the CPU (e.g. waiting for 16 | disk I/O). On Windows this is emulated by using a Windows API that 17 | spawns a thread which keeps running in background and updates results 18 | every 5 seconds, mimicking the UNIX behavior. Thus, on Windows, the 19 | first time this is called and for the next 5 seconds it will return a 20 | meaningless (0.0, 0.0, 0.0) vector. The numbers returned only make sense 21 | if related to the number of CPU cores installed on the system. So, for 22 | instance, a value of 3.14 on a system with 10 logical CPUs means that 23 | the system load was 31.4\% percent over the last N minutes. 24 | } 25 | \examples{ 26 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 27 | ps_loadavg() 28 | \dontshow{\}) # examplesIf} 29 | } 30 | -------------------------------------------------------------------------------- /man/ps_memory_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_memory_info} 4 | \alias{ps_memory_info} 5 | \alias{ps_memory_full_info} 6 | \title{Memory usage information} 7 | \usage{ 8 | ps_memory_info(p = ps_handle()) 9 | 10 | ps_memory_full_info(p = ps_handle()) 11 | } 12 | \arguments{ 13 | \item{p}{Process handle.} 14 | } 15 | \value{ 16 | Named real vector. 17 | } 18 | \description{ 19 | Memory usage information 20 | } 21 | \details{ 22 | \code{ps_memory_info()} returns information about memory usage. 23 | 24 | It returns a named vector. Portable fields: 25 | \itemize{ 26 | \item \code{rss}: "Resident Set Size", this is the non-swapped physical memory a 27 | process has used (bytes). On UNIX it matches "top"‘s 'RES' column (see doc). On 28 | Windows this is an alias for \code{wset} field and it matches "Memory" 29 | column of \code{taskmgr.exe}. 30 | \item \code{vmem}: "Virtual Memory Size", this is the total amount of virtual 31 | memory used by the process (bytes). On UNIX it matches "top"‘s 'VIRT' column 32 | (see doc). On Windows this is an alias for the \code{pagefile} field and 33 | it matches the "Working set (memory)" column of \code{taskmgr.exe}. 34 | } 35 | 36 | Non-portable fields: 37 | \itemize{ 38 | \item \code{shared}: (Linux) memory that could be potentially shared with other 39 | processes (bytes). This matches "top"‘s 'SHR' column (see doc). 40 | \item \code{text}: (Linux): aka 'TRS' (text resident set) the amount of memory 41 | devoted to executable code (bytes). This matches "top"‘s 'CODE' column (see 42 | doc). 43 | \item \code{data}: (Linux): aka 'DRS' (data resident set) the amount of physical 44 | memory devoted to other than executable code (bytes). It matches "top"‘s 45 | 'DATA' column (see doc). 46 | \item \code{lib}: (Linux): the memory used by shared libraries (bytes). 47 | \item \code{dirty}: (Linux): the amount of memory in dirty pages (bytes). 48 | \item \code{pfaults}: (macOS): number of page faults. 49 | \item \code{pageins}: (macOS): number of actual pageins. 50 | } 51 | 52 | For the explanation of Windows fields see the 53 | \href{https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-process_memory_counters_ex}{PROCESS_MEMORY_COUNTERS_EX} 54 | structure. 55 | 56 | \code{ps_memory_full_info()} returns all fields as \code{ps_memory_info()}, plus 57 | additional information, but typically takes slightly longer to run, and 58 | might not have access to some processes that \code{ps_memory_info()} can 59 | query: 60 | \itemize{ 61 | \item \code{maxrss} maximum resident set size over the process's lifetime. This 62 | only works for the calling process, otherwise it is \code{NA_real_}. 63 | \item \code{uss}: Unique Set Size, this is the memory which is unique to a 64 | process and which would be freed if the process was terminated right 65 | now. 66 | \item \code{pss} (Linux only): Proportional Set Size, is the amount of memory 67 | shared with other processes, accounted in a way that the amount is 68 | divided evenly between the processes that share it. I.e. if a process 69 | has 10 MBs all to itself and 10 MBs shared with another process its 70 | PSS will be 15 MBs. 71 | \item \code{swap} (Linux only): amount of memory that has been swapped out to 72 | disk. 73 | } 74 | 75 | They both throw a \code{zombie_process()} error for zombie processes. 76 | } 77 | \examples{ 78 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 79 | p <- ps_handle() 80 | p 81 | ps_memory_info(p) 82 | ps_memory_full_info(p) 83 | \dontshow{\}) # examplesIf} 84 | } 85 | \seealso{ 86 | Other process handle functions: 87 | \code{\link{ps_children}()}, 88 | \code{\link{ps_cmdline}()}, 89 | \code{\link{ps_connections}()}, 90 | \code{\link{ps_cpu_times}()}, 91 | \code{\link{ps_create_time}()}, 92 | \code{\link{ps_cwd}()}, 93 | \code{\link{ps_descent}()}, 94 | \code{\link{ps_environ}()}, 95 | \code{\link{ps_exe}()}, 96 | \code{\link{ps_handle}()}, 97 | \code{\link{ps_interrupt}()}, 98 | \code{\link{ps_is_running}()}, 99 | \code{\link{ps_kill}()}, 100 | \code{\link{ps_name}()}, 101 | \code{\link{ps_num_fds}()}, 102 | \code{\link{ps_num_threads}()}, 103 | \code{\link{ps_open_files}()}, 104 | \code{\link{ps_pid}()}, 105 | \code{\link{ps_ppid}()}, 106 | \code{\link{ps_resume}()}, 107 | \code{\link{ps_send_signal}()}, 108 | \code{\link{ps_shared_libs}()}, 109 | \code{\link{ps_status}()}, 110 | \code{\link{ps_suspend}()}, 111 | \code{\link{ps_terminal}()}, 112 | \code{\link{ps_terminate}()}, 113 | \code{\link{ps_uids}()}, 114 | \code{\link{ps_username}()} 115 | } 116 | \concept{process handle functions} 117 | -------------------------------------------------------------------------------- /man/ps_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_name} 4 | \alias{ps_name} 5 | \title{Process name} 6 | \usage{ 7 | ps_name(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Character scalar. 14 | } 15 | \description{ 16 | The name of the program, which is typically the name of the executable. 17 | } 18 | \details{ 19 | On Unix this can change, e.g. via an exec*() system call. 20 | 21 | \code{ps_name()} works on zombie processes. 22 | } 23 | \examples{ 24 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 25 | p <- ps_handle() 26 | p 27 | ps_name(p) 28 | ps_exe(p) 29 | ps_cmdline(p) 30 | \dontshow{\}) # examplesIf} 31 | } 32 | \seealso{ 33 | Other process handle functions: 34 | \code{\link{ps_children}()}, 35 | \code{\link{ps_cmdline}()}, 36 | \code{\link{ps_connections}()}, 37 | \code{\link{ps_cpu_times}()}, 38 | \code{\link{ps_create_time}()}, 39 | \code{\link{ps_cwd}()}, 40 | \code{\link{ps_descent}()}, 41 | \code{\link{ps_environ}()}, 42 | \code{\link{ps_exe}()}, 43 | \code{\link{ps_handle}()}, 44 | \code{\link{ps_interrupt}()}, 45 | \code{\link{ps_is_running}()}, 46 | \code{\link{ps_kill}()}, 47 | \code{\link{ps_memory_info}()}, 48 | \code{\link{ps_num_fds}()}, 49 | \code{\link{ps_num_threads}()}, 50 | \code{\link{ps_open_files}()}, 51 | \code{\link{ps_pid}()}, 52 | \code{\link{ps_ppid}()}, 53 | \code{\link{ps_resume}()}, 54 | \code{\link{ps_send_signal}()}, 55 | \code{\link{ps_shared_libs}()}, 56 | \code{\link{ps_status}()}, 57 | \code{\link{ps_suspend}()}, 58 | \code{\link{ps_terminal}()}, 59 | \code{\link{ps_terminate}()}, 60 | \code{\link{ps_uids}()}, 61 | \code{\link{ps_username}()} 62 | } 63 | \concept{process handle functions} 64 | -------------------------------------------------------------------------------- /man/ps_num_fds.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_num_fds} 4 | \alias{ps_num_fds} 5 | \title{Number of open file descriptors} 6 | \usage{ 7 | ps_num_fds(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Integer scalar. 14 | } 15 | \description{ 16 | Note that in some IDEs, e.g. RStudio or R.app on macOS, the IDE itself 17 | opens files from other threads, in addition to the files opened from the 18 | main R thread. 19 | } 20 | \details{ 21 | For a zombie process it throws a \code{zombie_process} error. 22 | } 23 | \examples{ 24 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 25 | p <- ps_handle() 26 | ps_num_fds(p) 27 | f <- file(tmp <- tempfile(), "w") 28 | ps_num_fds(p) 29 | close(f) 30 | unlink(tmp) 31 | ps_num_fds(p) 32 | \dontshow{\}) # examplesIf} 33 | } 34 | \seealso{ 35 | Other process handle functions: 36 | \code{\link{ps_children}()}, 37 | \code{\link{ps_cmdline}()}, 38 | \code{\link{ps_connections}()}, 39 | \code{\link{ps_cpu_times}()}, 40 | \code{\link{ps_create_time}()}, 41 | \code{\link{ps_cwd}()}, 42 | \code{\link{ps_descent}()}, 43 | \code{\link{ps_environ}()}, 44 | \code{\link{ps_exe}()}, 45 | \code{\link{ps_handle}()}, 46 | \code{\link{ps_interrupt}()}, 47 | \code{\link{ps_is_running}()}, 48 | \code{\link{ps_kill}()}, 49 | \code{\link{ps_memory_info}()}, 50 | \code{\link{ps_name}()}, 51 | \code{\link{ps_num_threads}()}, 52 | \code{\link{ps_open_files}()}, 53 | \code{\link{ps_pid}()}, 54 | \code{\link{ps_ppid}()}, 55 | \code{\link{ps_resume}()}, 56 | \code{\link{ps_send_signal}()}, 57 | \code{\link{ps_shared_libs}()}, 58 | \code{\link{ps_status}()}, 59 | \code{\link{ps_suspend}()}, 60 | \code{\link{ps_terminal}()}, 61 | \code{\link{ps_terminate}()}, 62 | \code{\link{ps_uids}()}, 63 | \code{\link{ps_username}()} 64 | } 65 | \concept{process handle functions} 66 | -------------------------------------------------------------------------------- /man/ps_num_threads.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_num_threads} 4 | \alias{ps_num_threads} 5 | \title{Number of threads} 6 | \usage{ 7 | ps_num_threads(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Integer scalar. 14 | } 15 | \description{ 16 | Throws a \code{zombie_process()} error for zombie processes. 17 | } 18 | \examples{ 19 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 20 | p <- ps_handle() 21 | p 22 | ps_num_threads(p) 23 | \dontshow{\}) # examplesIf} 24 | } 25 | \seealso{ 26 | Other process handle functions: 27 | \code{\link{ps_children}()}, 28 | \code{\link{ps_cmdline}()}, 29 | \code{\link{ps_connections}()}, 30 | \code{\link{ps_cpu_times}()}, 31 | \code{\link{ps_create_time}()}, 32 | \code{\link{ps_cwd}()}, 33 | \code{\link{ps_descent}()}, 34 | \code{\link{ps_environ}()}, 35 | \code{\link{ps_exe}()}, 36 | \code{\link{ps_handle}()}, 37 | \code{\link{ps_interrupt}()}, 38 | \code{\link{ps_is_running}()}, 39 | \code{\link{ps_kill}()}, 40 | \code{\link{ps_memory_info}()}, 41 | \code{\link{ps_name}()}, 42 | \code{\link{ps_num_fds}()}, 43 | \code{\link{ps_open_files}()}, 44 | \code{\link{ps_pid}()}, 45 | \code{\link{ps_ppid}()}, 46 | \code{\link{ps_resume}()}, 47 | \code{\link{ps_send_signal}()}, 48 | \code{\link{ps_shared_libs}()}, 49 | \code{\link{ps_status}()}, 50 | \code{\link{ps_suspend}()}, 51 | \code{\link{ps_terminal}()}, 52 | \code{\link{ps_terminate}()}, 53 | \code{\link{ps_uids}()}, 54 | \code{\link{ps_username}()} 55 | } 56 | \concept{process handle functions} 57 | -------------------------------------------------------------------------------- /man/ps_open_files.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_open_files} 4 | \alias{ps_open_files} 5 | \title{Open files of a process} 6 | \usage{ 7 | ps_open_files(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Data frame with columns: \code{fd} and \code{path}. \code{fd} is numeric 14 | file descriptor on POSIX systems, \code{NA} on Windows. \code{path} is an 15 | absolute path to the file. 16 | } 17 | \description{ 18 | Note that in some IDEs, e.g. RStudio or R.app on macOS, the IDE itself 19 | opens files from other threads, in addition to the files opened from the 20 | main R thread. 21 | } 22 | \details{ 23 | For a zombie process it throws a \code{zombie_process} error. 24 | } 25 | \examples{ 26 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 27 | p <- ps_handle() 28 | ps_open_files(p) 29 | f <- file(tmp <- tempfile(), "w") 30 | ps_open_files(p) 31 | close(f) 32 | unlink(tmp) 33 | ps_open_files(p) 34 | \dontshow{\}) # examplesIf} 35 | } 36 | \seealso{ 37 | Other process handle functions: 38 | \code{\link{ps_children}()}, 39 | \code{\link{ps_cmdline}()}, 40 | \code{\link{ps_connections}()}, 41 | \code{\link{ps_cpu_times}()}, 42 | \code{\link{ps_create_time}()}, 43 | \code{\link{ps_cwd}()}, 44 | \code{\link{ps_descent}()}, 45 | \code{\link{ps_environ}()}, 46 | \code{\link{ps_exe}()}, 47 | \code{\link{ps_handle}()}, 48 | \code{\link{ps_interrupt}()}, 49 | \code{\link{ps_is_running}()}, 50 | \code{\link{ps_kill}()}, 51 | \code{\link{ps_memory_info}()}, 52 | \code{\link{ps_name}()}, 53 | \code{\link{ps_num_fds}()}, 54 | \code{\link{ps_num_threads}()}, 55 | \code{\link{ps_pid}()}, 56 | \code{\link{ps_ppid}()}, 57 | \code{\link{ps_resume}()}, 58 | \code{\link{ps_send_signal}()}, 59 | \code{\link{ps_shared_libs}()}, 60 | \code{\link{ps_status}()}, 61 | \code{\link{ps_suspend}()}, 62 | \code{\link{ps_terminal}()}, 63 | \code{\link{ps_terminate}()}, 64 | \code{\link{ps_uids}()}, 65 | \code{\link{ps_username}()} 66 | } 67 | \concept{process handle functions} 68 | -------------------------------------------------------------------------------- /man/ps_os_type.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/os.R 3 | \name{ps_os_type} 4 | \alias{ps_os_type} 5 | \alias{ps_is_supported} 6 | \title{Query the type of the OS} 7 | \usage{ 8 | ps_os_type() 9 | 10 | ps_is_supported() 11 | } 12 | \value{ 13 | \code{ps_os_type} returns a named logical vector. The rest of the 14 | functions return a logical scalar. 15 | 16 | \code{ps_is_supported()} returns \code{TRUE} if ps supports the current platform. 17 | } 18 | \description{ 19 | Query the type of the OS 20 | } 21 | \examples{ 22 | ps_os_type() 23 | ps_is_supported() 24 | } 25 | -------------------------------------------------------------------------------- /man/ps_pid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_pid} 4 | \alias{ps_pid} 5 | \title{Pid of a process handle} 6 | \usage{ 7 | ps_pid(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Process id. 14 | } 15 | \description{ 16 | This function works even if the process has already finished. 17 | } 18 | \examples{ 19 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 20 | p <- ps_handle() 21 | p 22 | ps_pid(p) 23 | ps_pid(p) == Sys.getpid() 24 | \dontshow{\}) # examplesIf} 25 | } 26 | \seealso{ 27 | Other process handle functions: 28 | \code{\link{ps_children}()}, 29 | \code{\link{ps_cmdline}()}, 30 | \code{\link{ps_connections}()}, 31 | \code{\link{ps_cpu_times}()}, 32 | \code{\link{ps_create_time}()}, 33 | \code{\link{ps_cwd}()}, 34 | \code{\link{ps_descent}()}, 35 | \code{\link{ps_environ}()}, 36 | \code{\link{ps_exe}()}, 37 | \code{\link{ps_handle}()}, 38 | \code{\link{ps_interrupt}()}, 39 | \code{\link{ps_is_running}()}, 40 | \code{\link{ps_kill}()}, 41 | \code{\link{ps_memory_info}()}, 42 | \code{\link{ps_name}()}, 43 | \code{\link{ps_num_fds}()}, 44 | \code{\link{ps_num_threads}()}, 45 | \code{\link{ps_open_files}()}, 46 | \code{\link{ps_ppid}()}, 47 | \code{\link{ps_resume}()}, 48 | \code{\link{ps_send_signal}()}, 49 | \code{\link{ps_shared_libs}()}, 50 | \code{\link{ps_status}()}, 51 | \code{\link{ps_suspend}()}, 52 | \code{\link{ps_terminal}()}, 53 | \code{\link{ps_terminate}()}, 54 | \code{\link{ps_uids}()}, 55 | \code{\link{ps_username}()} 56 | } 57 | \concept{process handle functions} 58 | -------------------------------------------------------------------------------- /man/ps_pids.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_pids} 4 | \alias{ps_pids} 5 | \title{Ids of all processes on the system} 6 | \usage{ 7 | ps_pids() 8 | } 9 | \value{ 10 | Integer vector of process ids. 11 | } 12 | \description{ 13 | Ids of all processes on the system 14 | } 15 | -------------------------------------------------------------------------------- /man/ps_ppid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_ppid} 4 | \alias{ps_ppid} 5 | \alias{ps_parent} 6 | \title{Parent pid or parent process of a process} 7 | \usage{ 8 | ps_ppid(p = ps_handle()) 9 | 10 | ps_parent(p = ps_handle()) 11 | } 12 | \arguments{ 13 | \item{p}{Process handle.} 14 | } 15 | \value{ 16 | \code{ps_ppid()} returns and integer scalar, the pid of the parent 17 | of \code{p}. \code{ps_parent()} returns a \code{ps_handle}. 18 | } 19 | \description{ 20 | \code{ps_ppid()} returns the parent pid, \code{ps_parent()} returns a \code{ps_handle} 21 | of the parent. 22 | } 23 | \details{ 24 | On POSIX systems, if the parent process terminates, another process 25 | (typically the pid 1 process) is marked as parent. \code{ps_ppid()} and 26 | \code{ps_parent()} will return this process then. 27 | 28 | Both \code{ps_ppid()} and \code{ps_parent()} work for zombie processes. 29 | } 30 | \examples{ 31 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 32 | p <- ps_handle() 33 | p 34 | ps_ppid(p) 35 | ps_parent(p) 36 | \dontshow{\}) # examplesIf} 37 | } 38 | \seealso{ 39 | Other process handle functions: 40 | \code{\link{ps_children}()}, 41 | \code{\link{ps_cmdline}()}, 42 | \code{\link{ps_connections}()}, 43 | \code{\link{ps_cpu_times}()}, 44 | \code{\link{ps_create_time}()}, 45 | \code{\link{ps_cwd}()}, 46 | \code{\link{ps_descent}()}, 47 | \code{\link{ps_environ}()}, 48 | \code{\link{ps_exe}()}, 49 | \code{\link{ps_handle}()}, 50 | \code{\link{ps_interrupt}()}, 51 | \code{\link{ps_is_running}()}, 52 | \code{\link{ps_kill}()}, 53 | \code{\link{ps_memory_info}()}, 54 | \code{\link{ps_name}()}, 55 | \code{\link{ps_num_fds}()}, 56 | \code{\link{ps_num_threads}()}, 57 | \code{\link{ps_open_files}()}, 58 | \code{\link{ps_pid}()}, 59 | \code{\link{ps_resume}()}, 60 | \code{\link{ps_send_signal}()}, 61 | \code{\link{ps_shared_libs}()}, 62 | \code{\link{ps_status}()}, 63 | \code{\link{ps_suspend}()}, 64 | \code{\link{ps_terminal}()}, 65 | \code{\link{ps_terminate}()}, 66 | \code{\link{ps_uids}()}, 67 | \code{\link{ps_username}()} 68 | } 69 | \concept{process handle functions} 70 | -------------------------------------------------------------------------------- /man/ps_resume.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_resume} 4 | \alias{ps_resume} 5 | \title{Resume (continue) a stopped process} 6 | \usage{ 7 | ps_resume(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle or a list of process handles.} 11 | } 12 | \description{ 13 | Resume process execution with SIGCONT preemptively checking 14 | whether PID has been reused. On Windows this has the effect of resuming 15 | all process threads. 16 | } 17 | \examples{ 18 | \dontshow{if (ps::ps_is_supported() && ps::ps_os_type()["POSIX"] && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 19 | px <- processx::process$new("sleep", "10") 20 | p <- ps_handle(px$get_pid()) 21 | p 22 | ps_suspend(p) 23 | ps_status(p) 24 | ps_resume(p) 25 | ps_status(p) 26 | ps_kill(p) 27 | \dontshow{\}) # examplesIf} 28 | } 29 | \seealso{ 30 | Other process handle functions: 31 | \code{\link{ps_children}()}, 32 | \code{\link{ps_cmdline}()}, 33 | \code{\link{ps_connections}()}, 34 | \code{\link{ps_cpu_times}()}, 35 | \code{\link{ps_create_time}()}, 36 | \code{\link{ps_cwd}()}, 37 | \code{\link{ps_descent}()}, 38 | \code{\link{ps_environ}()}, 39 | \code{\link{ps_exe}()}, 40 | \code{\link{ps_handle}()}, 41 | \code{\link{ps_interrupt}()}, 42 | \code{\link{ps_is_running}()}, 43 | \code{\link{ps_kill}()}, 44 | \code{\link{ps_memory_info}()}, 45 | \code{\link{ps_name}()}, 46 | \code{\link{ps_num_fds}()}, 47 | \code{\link{ps_num_threads}()}, 48 | \code{\link{ps_open_files}()}, 49 | \code{\link{ps_pid}()}, 50 | \code{\link{ps_ppid}()}, 51 | \code{\link{ps_send_signal}()}, 52 | \code{\link{ps_shared_libs}()}, 53 | \code{\link{ps_status}()}, 54 | \code{\link{ps_suspend}()}, 55 | \code{\link{ps_terminal}()}, 56 | \code{\link{ps_terminate}()}, 57 | \code{\link{ps_uids}()}, 58 | \code{\link{ps_username}()} 59 | } 60 | \concept{process handle functions} 61 | -------------------------------------------------------------------------------- /man/ps_send_signal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_send_signal} 4 | \alias{ps_send_signal} 5 | \title{Send signal to a process} 6 | \usage{ 7 | ps_send_signal(p = ps_handle(), sig) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle, or a list of process handles.} 11 | 12 | \item{sig}{Signal number, see \code{\link[=signals]{signals()}}.} 13 | } 14 | \description{ 15 | Send a signal to the process. Not implemented on Windows. See 16 | \code{\link[=signals]{signals()}} for the list of signals on the current platform. 17 | } 18 | \details{ 19 | It checks if the process is still running, before sending the signal, 20 | to avoid signalling the wrong process, because of pid reuse. 21 | } 22 | \examples{ 23 | \dontshow{if (ps::ps_is_supported() && ps::ps_os_type()["POSIX"] && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 24 | px <- processx::process$new("sleep", "10") 25 | p <- ps_handle(px$get_pid()) 26 | p 27 | ps_send_signal(p, signals()$SIGINT) 28 | p 29 | ps_is_running(p) 30 | px$get_exit_status() 31 | \dontshow{\}) # examplesIf} 32 | } 33 | \seealso{ 34 | Other process handle functions: 35 | \code{\link{ps_children}()}, 36 | \code{\link{ps_cmdline}()}, 37 | \code{\link{ps_connections}()}, 38 | \code{\link{ps_cpu_times}()}, 39 | \code{\link{ps_create_time}()}, 40 | \code{\link{ps_cwd}()}, 41 | \code{\link{ps_descent}()}, 42 | \code{\link{ps_environ}()}, 43 | \code{\link{ps_exe}()}, 44 | \code{\link{ps_handle}()}, 45 | \code{\link{ps_interrupt}()}, 46 | \code{\link{ps_is_running}()}, 47 | \code{\link{ps_kill}()}, 48 | \code{\link{ps_memory_info}()}, 49 | \code{\link{ps_name}()}, 50 | \code{\link{ps_num_fds}()}, 51 | \code{\link{ps_num_threads}()}, 52 | \code{\link{ps_open_files}()}, 53 | \code{\link{ps_pid}()}, 54 | \code{\link{ps_ppid}()}, 55 | \code{\link{ps_resume}()}, 56 | \code{\link{ps_shared_libs}()}, 57 | \code{\link{ps_status}()}, 58 | \code{\link{ps_suspend}()}, 59 | \code{\link{ps_terminal}()}, 60 | \code{\link{ps_terminate}()}, 61 | \code{\link{ps_uids}()}, 62 | \code{\link{ps_username}()} 63 | } 64 | \concept{process handle functions} 65 | -------------------------------------------------------------------------------- /man/ps_shared_lib_users.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_shared_lib_users} 4 | \alias{ps_shared_lib_users} 5 | \title{List all processes that loaded a shared library} 6 | \usage{ 7 | ps_shared_lib_users(paths, user = ps_username(), filter = NULL) 8 | } 9 | \arguments{ 10 | \item{paths}{Character vector of paths of shared libraries to 11 | look up. They must be absolute paths. They don't need to exist. 12 | Forward slashes are converted to backward slashes on Windows, and 13 | the output will always have backward slashes in the paths.} 14 | 15 | \item{user}{Character scalar or \code{NULL}. If not \code{NULL}, then only 16 | the processes of this user are considered. It defaults to the 17 | current user.} 18 | 19 | \item{filter}{Character vector or \code{NULL}. If not NULL, then it is 20 | a vector of glob expressions, used to filter the process names.} 21 | } 22 | \value{ 23 | A data frame with columns: 24 | \itemize{ 25 | \item \code{dll}: the file name of the dll file, without the path, 26 | \item \code{path}: path to the shared library, 27 | \item \code{pid}: process ID of the process, 28 | \item \code{name}: name of the process, 29 | \item \code{username}: username of process owner, 30 | \item \code{ps_handle}: \code{ps_handle} object, that can be used to further 31 | query and manipulate the process. 32 | } 33 | } 34 | \description{ 35 | List all processes that loaded a shared library 36 | } 37 | \details{ 38 | \subsection{Notes:}{ 39 | 40 | This function currently only works on Windows. 41 | 42 | On Windows, a 32 bit R process can only list other 32 bit processes. 43 | Similarly, a 64 bit R process can only list other 64 bit processes. 44 | This is a limitation of the Windows API. 45 | 46 | Even though Windows file systems are (almost always) case 47 | insensitive, the matching of \code{paths}, \code{user} and also \code{filter} 48 | are case sensitive. This might change in the future. 49 | 50 | This function can be very slow on Windows, because it needs to 51 | enumerate all shared libraries of all processes in the system, 52 | unless the \code{filter} argument is set. Make sure you set \code{filter} 53 | if you can. 54 | 55 | If you want to look up multiple shared libraries, list all of them 56 | in \code{paths}, instead of calling \code{ps_shared_lib_users} for each 57 | individually. 58 | 59 | If you are after libraries loaded by R processes, you might want to 60 | set \code{filter} to \code{c("Rgui.exe", "Rterm.exe", "rsession.exe")} The 61 | last one is for RStudio. 62 | } 63 | } 64 | \examples{ 65 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check() && ps::ps_os_type()[["WINDOWS"]]) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 66 | dlls <- vapply(getLoadedDLLs(), "[[", character(1), "path") 67 | psdll <- dlls[["ps"]][[1]] 68 | r_procs <- c("Rgui.exe", "Rterm.exe", "rsession.exe") 69 | ps_shared_lib_users(psdll, filter = r_procs) 70 | \dontshow{\}) # examplesIf} 71 | } 72 | \seealso{ 73 | Other shared library tools: 74 | \code{\link{ps_shared_libs}()} 75 | } 76 | \concept{shared library tools} 77 | -------------------------------------------------------------------------------- /man/ps_shared_libs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_shared_libs} 4 | \alias{ps_shared_libs} 5 | \title{List the dynamically loaded libraries of a process} 6 | \usage{ 7 | ps_shared_libs(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Data frame with one column currently: \code{path}, the 14 | absolute path to the loaded module or shared library. On Windows 15 | the list includes the executable file itself. 16 | } 17 | \description{ 18 | Note: this function currently only works on Windows. 19 | } 20 | \examples{ 21 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check() && ps::ps_os_type()[["WINDOWS"]]) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 22 | # The loaded DLLs of the current process 23 | ps_shared_libs() 24 | \dontshow{\}) # examplesIf} 25 | } 26 | \seealso{ 27 | Other process handle functions: 28 | \code{\link{ps_children}()}, 29 | \code{\link{ps_cmdline}()}, 30 | \code{\link{ps_connections}()}, 31 | \code{\link{ps_cpu_times}()}, 32 | \code{\link{ps_create_time}()}, 33 | \code{\link{ps_cwd}()}, 34 | \code{\link{ps_descent}()}, 35 | \code{\link{ps_environ}()}, 36 | \code{\link{ps_exe}()}, 37 | \code{\link{ps_handle}()}, 38 | \code{\link{ps_interrupt}()}, 39 | \code{\link{ps_is_running}()}, 40 | \code{\link{ps_kill}()}, 41 | \code{\link{ps_memory_info}()}, 42 | \code{\link{ps_name}()}, 43 | \code{\link{ps_num_fds}()}, 44 | \code{\link{ps_num_threads}()}, 45 | \code{\link{ps_open_files}()}, 46 | \code{\link{ps_pid}()}, 47 | \code{\link{ps_ppid}()}, 48 | \code{\link{ps_resume}()}, 49 | \code{\link{ps_send_signal}()}, 50 | \code{\link{ps_status}()}, 51 | \code{\link{ps_suspend}()}, 52 | \code{\link{ps_terminal}()}, 53 | \code{\link{ps_terminate}()}, 54 | \code{\link{ps_uids}()}, 55 | \code{\link{ps_username}()} 56 | 57 | Other shared library tools: 58 | \code{\link{ps_shared_lib_users}()} 59 | } 60 | \concept{process handle functions} 61 | \concept{shared library tools} 62 | -------------------------------------------------------------------------------- /man/ps_status.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_status} 4 | \alias{ps_status} 5 | \title{Current process status} 6 | \usage{ 7 | ps_status(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Character scalar. 14 | } 15 | \description{ 16 | One of the following: 17 | \itemize{ 18 | \item \code{"idle"}: Process being created by fork, or process has been sleeping 19 | for a long time. macOS only. 20 | \item \code{"running"}: Currently runnable on macOS and Windows. Actually 21 | running on Linux. 22 | \item \code{"sleeping"} Sleeping on a wait or poll. 23 | \item \code{"disk_sleep"} Uninterruptible sleep, waiting for an I/O operation 24 | (Linux only). 25 | \item \code{"stopped"} Stopped, either by a job control signal or because it 26 | is being traced. 27 | \item \code{"uninterruptible"} Process is in uninterruptible wait. macOS only. 28 | \item \code{"tracing_stop"} Stopped for tracing (Linux only). 29 | \item \code{"zombie"} Zombie. Finished, but parent has not read out the exit 30 | status yet. 31 | \item \code{"dead"} Should never be seen (Linux). 32 | \item \code{"wake_kill"} Received fatal signal (Linux only). 33 | \item \code{"waking"} Paging (Linux only, not valid since the 2.6.xx kernel). 34 | } 35 | } 36 | \details{ 37 | It might return \code{NA_character_} on macOS. 38 | 39 | Works for zombie processes. 40 | } 41 | \section{Note on macOS}{ 42 | 43 | On macOS \code{ps_status()} often falls back to calling the external \code{ps} 44 | program, because macOS does not let R access the status of most other 45 | processes. Notably, it is usually able to access the status of other R 46 | processes. 47 | 48 | The external \code{ps} program always runs as the root user, and 49 | it also has special entitlements, so it can typically access the status 50 | of most processes. 51 | 52 | If this behavior is problematic for you, e.g. because calling an 53 | external program is too slow, set the \code{ps.no_external_ps} option to 54 | \code{TRUE}: 55 | 56 | \if{html}{\out{
}}\preformatted{options(ps.no_external_ps = TRUE) 57 | }\if{html}{\out{
}} 58 | 59 | Note that setting this option to \code{TRUE} will cause \code{ps_status()} to 60 | return \code{NA_character_} for most processes. 61 | } 62 | 63 | \examples{ 64 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 65 | p <- ps_handle() 66 | p 67 | ps_status(p) 68 | \dontshow{\}) # examplesIf} 69 | } 70 | \seealso{ 71 | Other process handle functions: 72 | \code{\link{ps_children}()}, 73 | \code{\link{ps_cmdline}()}, 74 | \code{\link{ps_connections}()}, 75 | \code{\link{ps_cpu_times}()}, 76 | \code{\link{ps_create_time}()}, 77 | \code{\link{ps_cwd}()}, 78 | \code{\link{ps_descent}()}, 79 | \code{\link{ps_environ}()}, 80 | \code{\link{ps_exe}()}, 81 | \code{\link{ps_handle}()}, 82 | \code{\link{ps_interrupt}()}, 83 | \code{\link{ps_is_running}()}, 84 | \code{\link{ps_kill}()}, 85 | \code{\link{ps_memory_info}()}, 86 | \code{\link{ps_name}()}, 87 | \code{\link{ps_num_fds}()}, 88 | \code{\link{ps_num_threads}()}, 89 | \code{\link{ps_open_files}()}, 90 | \code{\link{ps_pid}()}, 91 | \code{\link{ps_ppid}()}, 92 | \code{\link{ps_resume}()}, 93 | \code{\link{ps_send_signal}()}, 94 | \code{\link{ps_shared_libs}()}, 95 | \code{\link{ps_suspend}()}, 96 | \code{\link{ps_terminal}()}, 97 | \code{\link{ps_terminate}()}, 98 | \code{\link{ps_uids}()}, 99 | \code{\link{ps_username}()} 100 | } 101 | \concept{process handle functions} 102 | -------------------------------------------------------------------------------- /man/ps_string.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/string.R 3 | \name{ps_string} 4 | \alias{ps_string} 5 | \title{Encode a \code{ps_handle} as a short string} 6 | \usage{ 7 | ps_string(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | A process string (scalar character), that can be passed to 14 | \code{ps_handle()} in place of a pid. 15 | } 16 | \description{ 17 | A convenient format for passing between processes, naming semaphores, or 18 | using as a directory/file name. Will always be 14 alphanumeric characters, 19 | with the first and last characters guarantied to be letters. Encodes the 20 | pid and creation time for a process. 21 | } 22 | \examples{ 23 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 24 | (p <- ps_handle()) 25 | (str <- ps_string(p)) 26 | ps_handle(pid = str) 27 | \dontshow{\}) # examplesIf} 28 | } 29 | -------------------------------------------------------------------------------- /man/ps_suspend.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_suspend} 4 | \alias{ps_suspend} 5 | \title{Suspend (stop) the process} 6 | \usage{ 7 | ps_suspend(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle or a list of process handles.} 11 | } 12 | \description{ 13 | Suspend process execution with \code{SIGSTOP} preemptively checking 14 | whether PID has been reused. On Windows this has the effect of 15 | suspending all process threads. 16 | } 17 | \examples{ 18 | \dontshow{if (ps::ps_is_supported() && ps::ps_os_type()["POSIX"] && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 19 | px <- processx::process$new("sleep", "10") 20 | p <- ps_handle(px$get_pid()) 21 | p 22 | ps_suspend(p) 23 | ps_status(p) 24 | ps_resume(p) 25 | ps_status(p) 26 | ps_kill(p) 27 | \dontshow{\}) # examplesIf} 28 | } 29 | \seealso{ 30 | Other process handle functions: 31 | \code{\link{ps_children}()}, 32 | \code{\link{ps_cmdline}()}, 33 | \code{\link{ps_connections}()}, 34 | \code{\link{ps_cpu_times}()}, 35 | \code{\link{ps_create_time}()}, 36 | \code{\link{ps_cwd}()}, 37 | \code{\link{ps_descent}()}, 38 | \code{\link{ps_environ}()}, 39 | \code{\link{ps_exe}()}, 40 | \code{\link{ps_handle}()}, 41 | \code{\link{ps_interrupt}()}, 42 | \code{\link{ps_is_running}()}, 43 | \code{\link{ps_kill}()}, 44 | \code{\link{ps_memory_info}()}, 45 | \code{\link{ps_name}()}, 46 | \code{\link{ps_num_fds}()}, 47 | \code{\link{ps_num_threads}()}, 48 | \code{\link{ps_open_files}()}, 49 | \code{\link{ps_pid}()}, 50 | \code{\link{ps_ppid}()}, 51 | \code{\link{ps_resume}()}, 52 | \code{\link{ps_send_signal}()}, 53 | \code{\link{ps_shared_libs}()}, 54 | \code{\link{ps_status}()}, 55 | \code{\link{ps_terminal}()}, 56 | \code{\link{ps_terminate}()}, 57 | \code{\link{ps_uids}()}, 58 | \code{\link{ps_username}()} 59 | } 60 | \concept{process handle functions} 61 | -------------------------------------------------------------------------------- /man/ps_system_cpu_times.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_system_cpu_times} 4 | \alias{ps_system_cpu_times} 5 | \title{System CPU times.} 6 | \usage{ 7 | ps_system_cpu_times() 8 | } 9 | \value{ 10 | Named list 11 | } 12 | \description{ 13 | Every attribute represents the seconds the CPU has spent in the given 14 | mode. The attributes availability varies depending on the platform: 15 | \itemize{ 16 | \item \code{user}: time spent by normal processes executing in user mode; 17 | on Linux this also includes guest time. 18 | \item \code{system}: time spent by processes executing in kernel mode. 19 | \item \code{idle}: time spent doing nothing. 20 | } 21 | } 22 | \details{ 23 | Platform-specific fields: 24 | \itemize{ 25 | \item \code{nice} (UNIX): time spent by niced (prioritized) processes executing 26 | in user mode; on Linux this also includes guest_nice time. 27 | \item \code{iowait} (Linux): time spent waiting for I/O to complete. This is not 28 | accounted in idle time counter. 29 | \item \code{irq} (Linux): time spent for servicing hardware interrupts. 30 | \item \code{softirq} (Linux): time spent for servicing software interrupts. 31 | \item \code{steal} (Linux 2.6.11+): time spent by other operating systems 32 | running in a virtualized environment. 33 | \item \code{guest} (Linux 2.6.24+): time spent running a virtual CPU for guest 34 | operating systems under the control of the Linux kernel. 35 | \item \code{guest_nice} (Linux 3.2.0+): time spent running a niced guest 36 | (virtual CPU for guest operating systems under the control of the 37 | Linux kernel). 38 | } 39 | } 40 | \examples{ 41 | \dontshow{if (ps::ps_is_supported()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 42 | ps_system_cpu_times() 43 | \dontshow{\}) # examplesIf} 44 | } 45 | -------------------------------------------------------------------------------- /man/ps_system_memory.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/memory.R 3 | \name{ps_system_memory} 4 | \alias{ps_system_memory} 5 | \title{Statistics about system memory usage} 6 | \usage{ 7 | ps_system_memory() 8 | } 9 | \value{ 10 | Named list. All numbers are in bytes: 11 | \itemize{ 12 | \item \code{total}: total physical memory (exclusive swap). 13 | \item \code{avail} the memory that can be given instantly to processes without 14 | the system going into swap. This is calculated by summing different 15 | memory values depending on the platform and it is supposed to be used 16 | to monitor actual memory usage in a cross platform fashion. 17 | \item \code{percent}: Percentage of memory that is taken. 18 | \item \code{used}: memory used, calculated differently depending on 19 | the platform and designed for informational purposes only. 20 | \code{total} - \code{free} does not necessarily match \code{used}. 21 | \item \code{free}: memory not being used at all (zeroed) that is 22 | readily available; note that this doesn’t reflect the actual memory 23 | available (use \code{available} instead). \code{total} - \code{used} does not 24 | necessarily match \code{free}. 25 | \item \code{active}: (Unix only) memory currently in use or very recently used, 26 | and so it is in RAM. 27 | \item \code{inactive}: (Unix only) memory that is marked as not used. 28 | \item \code{wired}: (macOS only) memory that is marked to always stay in RAM. It 29 | is never moved to disk. 30 | \item \code{buffers}: (Linux only) cache for things like file system metadata. 31 | \item \code{cached}: (Linux only) cache for various things. 32 | \item \code{shared}: (Linux only) memory that may be simultaneously accessed by 33 | multiple processes. 34 | \item \code{slab}: (Linux only) in-kernel data structures cache. 35 | } 36 | } 37 | \description{ 38 | Statistics about system memory usage 39 | } 40 | \examples{ 41 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 42 | ps_system_memory() 43 | \dontshow{\}) # examplesIf} 44 | } 45 | \seealso{ 46 | Other memory functions: 47 | \code{\link{ps_system_swap}()} 48 | } 49 | \concept{memory functions} 50 | -------------------------------------------------------------------------------- /man/ps_system_swap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/memory.R 3 | \name{ps_system_swap} 4 | \alias{ps_system_swap} 5 | \title{System swap memory statistics} 6 | \usage{ 7 | ps_system_swap() 8 | } 9 | \value{ 10 | Named list. All numbers are in bytes: 11 | \itemize{ 12 | \item \code{total}: total swap memory. 13 | \item \code{used}: used swap memory. 14 | \item \code{free}: free swap memory. 15 | \item \code{percent}: the percentage usage. 16 | \item \code{sin}: the number of bytes the system has swapped in from disk 17 | (cumulative). This is \code{NA} on Windows. 18 | \item \code{sout}: the number of bytes the system has swapped out from disk 19 | (cumulative). This is \code{NA} on Windows. 20 | } 21 | } 22 | \description{ 23 | System swap memory statistics 24 | } 25 | \examples{ 26 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 27 | ps_system_swap() 28 | \dontshow{\}) # examplesIf} 29 | } 30 | \seealso{ 31 | Other memory functions: 32 | \code{\link{ps_system_memory}()} 33 | } 34 | \concept{memory functions} 35 | -------------------------------------------------------------------------------- /man/ps_terminal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_terminal} 4 | \alias{ps_terminal} 5 | \title{Terminal device of the process} 6 | \usage{ 7 | ps_terminal(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | Character scalar. 14 | } 15 | \description{ 16 | Returns the terminal of the process. Not implemented on Windows, always 17 | returns \code{NA_character_}. On Unix it returns \code{NA_character_} if the 18 | process has no terminal. 19 | } 20 | \details{ 21 | Works for zombie processes. 22 | } 23 | \examples{ 24 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 25 | p <- ps_handle() 26 | p 27 | ps_terminal(p) 28 | \dontshow{\}) # examplesIf} 29 | } 30 | \seealso{ 31 | Other process handle functions: 32 | \code{\link{ps_children}()}, 33 | \code{\link{ps_cmdline}()}, 34 | \code{\link{ps_connections}()}, 35 | \code{\link{ps_cpu_times}()}, 36 | \code{\link{ps_create_time}()}, 37 | \code{\link{ps_cwd}()}, 38 | \code{\link{ps_descent}()}, 39 | \code{\link{ps_environ}()}, 40 | \code{\link{ps_exe}()}, 41 | \code{\link{ps_handle}()}, 42 | \code{\link{ps_interrupt}()}, 43 | \code{\link{ps_is_running}()}, 44 | \code{\link{ps_kill}()}, 45 | \code{\link{ps_memory_info}()}, 46 | \code{\link{ps_name}()}, 47 | \code{\link{ps_num_fds}()}, 48 | \code{\link{ps_num_threads}()}, 49 | \code{\link{ps_open_files}()}, 50 | \code{\link{ps_pid}()}, 51 | \code{\link{ps_ppid}()}, 52 | \code{\link{ps_resume}()}, 53 | \code{\link{ps_send_signal}()}, 54 | \code{\link{ps_shared_libs}()}, 55 | \code{\link{ps_status}()}, 56 | \code{\link{ps_suspend}()}, 57 | \code{\link{ps_terminate}()}, 58 | \code{\link{ps_uids}()}, 59 | \code{\link{ps_username}()} 60 | } 61 | \concept{process handle functions} 62 | -------------------------------------------------------------------------------- /man/ps_terminate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_terminate} 4 | \alias{ps_terminate} 5 | \title{Terminate a Unix process} 6 | \usage{ 7 | ps_terminate(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle or a list of process handles.} 11 | } 12 | \description{ 13 | Send a \code{SIGTERM} signal to the process. Not implemented on Windows. 14 | } 15 | \details{ 16 | Checks if the process is still running, to work around pid reuse. 17 | } 18 | \examples{ 19 | \dontshow{if (ps::ps_is_supported() && ps::ps_os_type()["POSIX"] && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 20 | px <- processx::process$new("sleep", "10") 21 | p <- ps_handle(px$get_pid()) 22 | p 23 | ps_terminate(p) 24 | p 25 | ps_is_running(p) 26 | px$get_exit_status() 27 | \dontshow{\}) # examplesIf} 28 | } 29 | \seealso{ 30 | Other process handle functions: 31 | \code{\link{ps_children}()}, 32 | \code{\link{ps_cmdline}()}, 33 | \code{\link{ps_connections}()}, 34 | \code{\link{ps_cpu_times}()}, 35 | \code{\link{ps_create_time}()}, 36 | \code{\link{ps_cwd}()}, 37 | \code{\link{ps_descent}()}, 38 | \code{\link{ps_environ}()}, 39 | \code{\link{ps_exe}()}, 40 | \code{\link{ps_handle}()}, 41 | \code{\link{ps_interrupt}()}, 42 | \code{\link{ps_is_running}()}, 43 | \code{\link{ps_kill}()}, 44 | \code{\link{ps_memory_info}()}, 45 | \code{\link{ps_name}()}, 46 | \code{\link{ps_num_fds}()}, 47 | \code{\link{ps_num_threads}()}, 48 | \code{\link{ps_open_files}()}, 49 | \code{\link{ps_pid}()}, 50 | \code{\link{ps_ppid}()}, 51 | \code{\link{ps_resume}()}, 52 | \code{\link{ps_send_signal}()}, 53 | \code{\link{ps_shared_libs}()}, 54 | \code{\link{ps_status}()}, 55 | \code{\link{ps_suspend}()}, 56 | \code{\link{ps_terminal}()}, 57 | \code{\link{ps_uids}()}, 58 | \code{\link{ps_username}()} 59 | } 60 | \concept{process handle functions} 61 | -------------------------------------------------------------------------------- /man/ps_tty_size.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_tty_size} 4 | \alias{ps_tty_size} 5 | \title{Query the size of the current terminal} 6 | \usage{ 7 | ps_tty_size() 8 | } 9 | \description{ 10 | If the standard output of the current R process is not a terminal, 11 | e.g. because it is redirected to a file, or the R process is running in 12 | a GUI, then it will throw an error. You need to handle this error if 13 | you want to use this function in a package. 14 | } 15 | \details{ 16 | If an error happens, the error message is different depending on 17 | what type of device the standard output is. Some common error messages 18 | are: 19 | \itemize{ 20 | \item "Inappropriate ioctl for device." 21 | \item "Operation not supported on socket." 22 | \item "Operation not supported by device." 23 | } 24 | 25 | Whatever the error message, \code{ps_tty_size} always fails with an error of 26 | class \code{ps_unknown_tty_size}, which you can catch. 27 | } 28 | \examples{ 29 | # An example that falls back to the 'width' option 30 | tryCatch( 31 | ps_tty_size(), 32 | ps_unknown_tty_size = function(err) { 33 | c(width = getOption("width"), height = NA_integer_) 34 | } 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /man/ps_uids.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_uids} 4 | \alias{ps_uids} 5 | \alias{ps_gids} 6 | \title{User ids and group ids of the process} 7 | \usage{ 8 | ps_uids(p = ps_handle()) 9 | 10 | ps_gids(p = ps_handle()) 11 | } 12 | \arguments{ 13 | \item{p}{Process handle.} 14 | } 15 | \value{ 16 | Named integer vector of length 3, with names: \code{real}, 17 | \code{effective} and \code{saved}. 18 | } 19 | \description{ 20 | User ids and group ids of the process. Both return integer vectors with 21 | names: \code{real}, \code{effective} and \code{saved}. 22 | } 23 | \details{ 24 | Both work for zombie processes. 25 | 26 | They are not implemented on Windows, they throw a \code{not_implemented} 27 | error. 28 | } 29 | \examples{ 30 | \dontshow{if (ps::ps_is_supported() && ps::ps_os_type()["POSIX"] && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 31 | p <- ps_handle() 32 | p 33 | ps_uids(p) 34 | ps_gids(p) 35 | \dontshow{\}) # examplesIf} 36 | } 37 | \seealso{ 38 | \code{\link[=ps_username]{ps_username()}} returns a user \emph{name} and works on all 39 | platforms. 40 | 41 | Other process handle functions: 42 | \code{\link{ps_children}()}, 43 | \code{\link{ps_cmdline}()}, 44 | \code{\link{ps_connections}()}, 45 | \code{\link{ps_cpu_times}()}, 46 | \code{\link{ps_create_time}()}, 47 | \code{\link{ps_cwd}()}, 48 | \code{\link{ps_descent}()}, 49 | \code{\link{ps_environ}()}, 50 | \code{\link{ps_exe}()}, 51 | \code{\link{ps_handle}()}, 52 | \code{\link{ps_interrupt}()}, 53 | \code{\link{ps_is_running}()}, 54 | \code{\link{ps_kill}()}, 55 | \code{\link{ps_memory_info}()}, 56 | \code{\link{ps_name}()}, 57 | \code{\link{ps_num_fds}()}, 58 | \code{\link{ps_num_threads}()}, 59 | \code{\link{ps_open_files}()}, 60 | \code{\link{ps_pid}()}, 61 | \code{\link{ps_ppid}()}, 62 | \code{\link{ps_resume}()}, 63 | \code{\link{ps_send_signal}()}, 64 | \code{\link{ps_shared_libs}()}, 65 | \code{\link{ps_status}()}, 66 | \code{\link{ps_suspend}()}, 67 | \code{\link{ps_terminal}()}, 68 | \code{\link{ps_terminate}()}, 69 | \code{\link{ps_username}()} 70 | } 71 | \concept{process handle functions} 72 | -------------------------------------------------------------------------------- /man/ps_username.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_username} 4 | \alias{ps_username} 5 | \title{Owner of the process} 6 | \usage{ 7 | ps_username(p = ps_handle()) 8 | } 9 | \arguments{ 10 | \item{p}{Process handle.} 11 | } 12 | \value{ 13 | String scalar. 14 | } 15 | \description{ 16 | The name of the user that owns the process. On Unix it is calculated 17 | from the real user id. 18 | } 19 | \details{ 20 | On Unix, a numeric uid id returned if the uid is not in the user 21 | database, thus a username cannot be determined. 22 | 23 | Works for zombie processes. 24 | } 25 | \examples{ 26 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 27 | p <- ps_handle() 28 | p 29 | ps_username(p) 30 | \dontshow{\}) # examplesIf} 31 | } 32 | \seealso{ 33 | Other process handle functions: 34 | \code{\link{ps_children}()}, 35 | \code{\link{ps_cmdline}()}, 36 | \code{\link{ps_connections}()}, 37 | \code{\link{ps_cpu_times}()}, 38 | \code{\link{ps_create_time}()}, 39 | \code{\link{ps_cwd}()}, 40 | \code{\link{ps_descent}()}, 41 | \code{\link{ps_environ}()}, 42 | \code{\link{ps_exe}()}, 43 | \code{\link{ps_handle}()}, 44 | \code{\link{ps_interrupt}()}, 45 | \code{\link{ps_is_running}()}, 46 | \code{\link{ps_kill}()}, 47 | \code{\link{ps_memory_info}()}, 48 | \code{\link{ps_name}()}, 49 | \code{\link{ps_num_fds}()}, 50 | \code{\link{ps_num_threads}()}, 51 | \code{\link{ps_open_files}()}, 52 | \code{\link{ps_pid}()}, 53 | \code{\link{ps_ppid}()}, 54 | \code{\link{ps_resume}()}, 55 | \code{\link{ps_send_signal}()}, 56 | \code{\link{ps_shared_libs}()}, 57 | \code{\link{ps_status}()}, 58 | \code{\link{ps_suspend}()}, 59 | \code{\link{ps_terminal}()}, 60 | \code{\link{ps_terminate}()}, 61 | \code{\link{ps_uids}()} 62 | } 63 | \concept{process handle functions} 64 | -------------------------------------------------------------------------------- /man/ps_users.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{ps_users} 4 | \alias{ps_users} 5 | \title{List users connected to the system} 6 | \usage{ 7 | ps_users() 8 | } 9 | \value{ 10 | A data frame with columns 11 | \code{username}, \code{tty}, \code{hostname}, \code{start_time}, \code{pid}. \code{tty} and \code{pid} 12 | are \code{NA} on Windows. \code{pid} is the process id of the login process. 13 | For local users the \code{hostname} column is the empty string. 14 | } 15 | \description{ 16 | List users connected to the system 17 | } 18 | -------------------------------------------------------------------------------- /man/ps_wait.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/low-level.R 3 | \name{ps_wait} 4 | \alias{ps_wait} 5 | \title{Wait for one or more processes to terminate, with a timeout} 6 | \usage{ 7 | ps_wait(p, timeout = -1) 8 | } 9 | \arguments{ 10 | \item{p}{A process handle, or a list of process handles. The 11 | process(es) to wait for.} 12 | 13 | \item{timeout}{Timeout in milliseconds. If -1, \code{ps_wait()} will wait 14 | indefinitely (or until it is interrupted). If 0, then it checks which 15 | processes have already terminated, and returns immediately.} 16 | } 17 | \value{ 18 | Logical vector, with one value of each process in \code{p}. 19 | For processes that terminated it contains a \code{TRUE} value. For 20 | processes that are still running it contains a \code{FALSE} value. 21 | } 22 | \description{ 23 | This function supports interruption with SIGINT on Unix, or CTRL+C 24 | or CTRL+BREAK on Windows. 25 | } 26 | \examples{ 27 | \dontshow{if (ps::ps_is_supported() && ! ps:::is_cran_check() && ps::ps_os_type()["POSIX"]) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 28 | # this example calls `sleep`, so it only works on Unix 29 | p1 <- processx::process$new("sleep", "100") 30 | p2 <- processx::process$new("sleep", "100") 31 | 32 | # returns c(FALSE, FALSE) immediately if p1 and p2 are running 33 | ps_wait(list(p1$as_ps_handle(), p2$as_ps_handle()), 0) 34 | 35 | # timeouts at one second 36 | ps_wait(list(p1$as_ps_handle(), p2$as_ps_handle()), 1000) 37 | 38 | p1$kill() 39 | p2$kill() 40 | # returns c(TRUE, TRUE) immediately 41 | ps_wait(list(p1$as_ps_handle(), p2$as_ps_handle()), 1000) 42 | \dontshow{\}) # examplesIf} 43 | } 44 | -------------------------------------------------------------------------------- /man/signals.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/posix.R 3 | \name{signals} 4 | \alias{signals} 5 | \title{List of all supported signals} 6 | \usage{ 7 | signals() 8 | } 9 | \value{ 10 | List of integers, named by signal names. 11 | } 12 | \description{ 13 | Only the signals supported by the current platform are included. 14 | } 15 | -------------------------------------------------------------------------------- /ps.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | StripTrailingWhitespace: Yes 16 | 17 | BuildType: Package 18 | PackageUseDevtools: Yes 19 | PackageInstallArgs: --no-multiarch --with-keep.source 20 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/Makevars.in: -------------------------------------------------------------------------------- 1 | 2 | OBJECTS = @OBJECTS@ 3 | 4 | PKG_LIBS = @LIBS@ 5 | 6 | .PHONY: all clean 7 | 8 | all: px @TARGETS@ $(SHLIB) 9 | 10 | px: px.c 11 | $(CC) $(CFLAGS) $(LDFLAGS) -Wall px.c -o px 12 | 13 | interrupt: interrupt.c 14 | $(CC) $(CFLAGS) $(LDFLAGS) -Wall interrupt.c -o interrupt 15 | 16 | clean: 17 | rm -rf $(SHLIB) $(OBJECTS) px.exe px interrupt.exe interrupt 18 | -------------------------------------------------------------------------------- /src/api-common.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _GNU_SOURCE 3 | #define _GNU_SOURCE 1 4 | #endif 5 | 6 | #define R_USE_C99_IN_CXX 1 7 | #include 8 | 9 | #include "ps-internal.h" 10 | 11 | SEXP psll_pid(SEXP p) { 12 | ps_handle_t *handle = R_ExternalPtrAddr(p); 13 | if (!handle) error("Process pointer cleaned up already"); 14 | return ScalarInteger(handle->pid); 15 | } 16 | 17 | SEXP psll_create_time(SEXP p) { 18 | ps_handle_t *handle = R_ExternalPtrAddr(p); 19 | 20 | if (!handle) error("Process pointer cleaned up already"); 21 | return ScalarReal(handle->create_time); 22 | } 23 | 24 | SEXP ps__os_type(void) { 25 | SEXP res, names; 26 | 27 | PROTECT(res = allocVector(LGLSXP, 4)); 28 | PROTECT(names = allocVector(STRSXP, 4)); 29 | 30 | SET_STRING_ELT(names, 0, mkChar("POSIX")); 31 | SET_STRING_ELT(names, 1, mkChar("WINDOWS")); 32 | SET_STRING_ELT(names, 2, mkChar("LINUX")); 33 | SET_STRING_ELT(names, 3, mkChar("MACOS")); 34 | 35 | /* SET_STRING_ELT(names, 4, mkChar("FREEBSD")); */ 36 | /* SET_STRING_ELT(names, 5, mkChar("OPENBSD")); */ 37 | /* SET_STRING_ELT(names, 6, mkChar("NETBSD")); */ 38 | /* SET_STRING_ELT(names, 7, mkChar("BSD")); */ 39 | /* SET_STRING_ELT(names, 8, mkChar("SUNOS")); */ 40 | /* SET_STRING_ELT(names, 9, mkChar("AIX")); */ 41 | 42 | LOGICAL(res)[0] = LOGICAL(res)[1] = LOGICAL(res)[2] = LOGICAL(res)[3] = 0; 43 | 44 | #ifdef PS__POSIX 45 | LOGICAL(res)[0] = 1; 46 | #endif 47 | #ifdef PS__WINDOWS 48 | LOGICAL(res)[1] = 1; 49 | #endif 50 | #ifdef PS__LINUX 51 | LOGICAL(res)[2] = 1; 52 | #endif 53 | #ifdef PS__MACOS 54 | LOGICAL(res)[3] = 1; 55 | #endif 56 | 57 | /* #ifdef PS__FREEBSD */ 58 | /* LOGICAL(res)[4] = 1; */ 59 | /* #endif */ 60 | /* #ifdef PS__OPENBSD */ 61 | /* LOGICAL(res)[5] = 1; */ 62 | /* #endif */ 63 | /* #ifdef PS__NETBSD */ 64 | /* LOGICAL(res)[6] = 1; */ 65 | /* #endif */ 66 | /* #ifdef PS__BSD */ 67 | /* LOGICAL(res)[7] = 1; */ 68 | /* #endif */ 69 | /* #ifdef PS__SUNOS */ 70 | /* LOGICAL(res)[8] = 1; */ 71 | /* #endif */ 72 | /* #ifdef PS__AIX */ 73 | /* LOGICAL(res)[9] = 1; */ 74 | /* #endif */ 75 | 76 | setAttrib(res, R_NamesSymbol, names); 77 | UNPROTECT(2); 78 | return res; 79 | } 80 | -------------------------------------------------------------------------------- /src/arch/macos/apps.m: -------------------------------------------------------------------------------- 1 | #include 2 | #import 3 | 4 | #include 5 | #include 6 | 7 | SEXP ps__list_apps(void) { 8 | // need to run the event loop a bit, to process updates for the 9 | // currently running applications 10 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); 11 | NSWorkspace *ws = [NSWorkspace sharedWorkspace]; 12 | NSArray *apps = [ws runningApplications]; 13 | 14 | const char *nms[] = { 15 | "name", 16 | "bundle_identifier", 17 | "bundle_url", 18 | "arch", 19 | "executable_url", 20 | "launch_date", 21 | "finished_launching", 22 | "pid", 23 | "active", 24 | "activation_policy", 25 | "" 26 | }; 27 | SEXP res = PROTECT(Rf_mkNamed(VECSXP, nms)); 28 | NSUInteger count = [apps count]; 29 | SET_VECTOR_ELT(res, 0, Rf_allocVector(STRSXP, count)); 30 | SET_VECTOR_ELT(res, 1, Rf_allocVector(STRSXP, count)); 31 | SET_VECTOR_ELT(res, 2, Rf_allocVector(STRSXP, count)); 32 | SET_VECTOR_ELT(res, 3, Rf_allocVector(INTSXP, count)); 33 | SET_VECTOR_ELT(res, 4, Rf_allocVector(STRSXP, count)); 34 | SET_VECTOR_ELT(res, 5, Rf_allocVector(STRSXP, count)); 35 | SET_VECTOR_ELT(res, 6, Rf_allocVector(LGLSXP, count)); 36 | SET_VECTOR_ELT(res, 7, Rf_allocVector(INTSXP, count)); 37 | SET_VECTOR_ELT(res, 8, Rf_allocVector(LGLSXP, count)); 38 | SET_VECTOR_ELT(res, 9, Rf_allocVector(STRSXP, count)); 39 | 40 | for (NSUInteger i = 0; i < count; i++) { 41 | NSRunningApplication *app = [apps objectAtIndex:i]; 42 | 43 | const char *name = [app.localizedName UTF8String]; 44 | SET_STRING_ELT(VECTOR_ELT(res, 0), i, name ? Rf_mkCharCE(name, CE_UTF8) : NA_STRING); 45 | const char *bid = [app.bundleIdentifier UTF8String]; 46 | SET_STRING_ELT(VECTOR_ELT(res, 1), i, bid ? Rf_mkCharCE(bid, CE_UTF8) : NA_STRING); 47 | const char *burl = app.bundleURL ? [app.bundleURL.absoluteString UTF8String] : 0; 48 | SET_STRING_ELT(VECTOR_ELT(res, 2), i, burl ? Rf_mkCharCE(burl, CE_UTF8) : NA_STRING); 49 | INTEGER(VECTOR_ELT(res, 3))[i] = app.executableArchitecture; 50 | const char *eurl = app.executableURL ? [app.executableURL.absoluteString UTF8String] : 0; 51 | SET_STRING_ELT(VECTOR_ELT(res, 4), i, eurl ? Rf_mkCharCE(eurl, CE_UTF8) : NA_STRING); 52 | const char *ld = app.launchDate ? [app.launchDate.description UTF8String] : 0; 53 | SET_STRING_ELT(VECTOR_ELT(res, 5), i, ld ? Rf_mkCharCE(ld, CE_UTF8) : NA_STRING); 54 | LOGICAL(VECTOR_ELT(res, 6))[i] = app.finishedLaunching; 55 | INTEGER(VECTOR_ELT(res, 7))[i] = app.processIdentifier; 56 | LOGICAL(VECTOR_ELT(res, 8))[i] = app.active; 57 | 58 | if (app.activationPolicy == NSApplicationActivationPolicyRegular) { 59 | SET_STRING_ELT(VECTOR_ELT(res, 9), i, Rf_mkChar("regular")); 60 | } else if (app.activationPolicy == NSApplicationActivationPolicyAccessory) { 61 | SET_STRING_ELT(VECTOR_ELT(res, 9), i, Rf_mkChar("accessory")); 62 | } else if (app.activationPolicy == NSApplicationActivationPolicyProhibited) { 63 | SET_STRING_ELT(VECTOR_ELT(res, 9), i, Rf_mkChar("prohibited")); 64 | } else { 65 | SET_STRING_ELT(VECTOR_ELT(res, 9), i, NA_STRING); 66 | } 67 | } 68 | 69 | UNPROTECT(1); 70 | return res; 71 | } 72 | -------------------------------------------------------------------------------- /src/arch/macos/process_info.h: -------------------------------------------------------------------------------- 1 | 2 | #include "../../common.h" 3 | 4 | typedef struct kinfo_proc kinfo_proc; 5 | 6 | int ps__get_argmax(void); 7 | int ps__get_kinfo_proc(long pid, struct kinfo_proc *kp); 8 | int ps__get_proc_list(kinfo_proc **procList, size_t *procCount); 9 | int ps__proc_pidinfo( 10 | long pid, int flavor, uint64_t arg, void *pti, int size); 11 | SEXP ps__get_cmdline(long pid); 12 | SEXP ps__get_environ(long pid); 13 | -------------------------------------------------------------------------------- /src/arch/windows/process_handles.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __PROCESS_HANDLES_H__ 3 | #define __PROCESS_HANDLES_H__ 4 | 5 | #ifndef UNICODE 6 | #define UNICODE 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #ifndef NT_SUCCESS 17 | #define NT_SUCCESS(x) ((x) >= 0) 18 | #endif 19 | 20 | #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 21 | #define ObjectBasicInformation 0 22 | #define ObjectNameInformation 1 23 | #define ObjectTypeInformation 2 24 | #define HANDLE_TYPE_FILE 28 25 | #define NTQO_TIMEOUT 100 26 | 27 | typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( 28 | ULONG SystemInformationClass, 29 | PVOID SystemInformation, 30 | ULONG SystemInformationLength, 31 | PULONG ReturnLength 32 | ); 33 | 34 | typedef NTSTATUS (NTAPI *_NtQueryObject)( 35 | HANDLE ObjectHandle, 36 | ULONG ObjectInformationClass, 37 | PVOID ObjectInformation, 38 | ULONG ObjectInformationLength, 39 | PULONG ReturnLength 40 | ); 41 | 42 | // Undocumented FILE_INFORMATION_CLASS: FileNameInformation 43 | static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64; 44 | 45 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { 46 | PVOID Object; 47 | HANDLE UniqueProcessId; 48 | HANDLE HandleValue; 49 | ULONG GrantedAccess; 50 | USHORT CreatorBackTraceIndex; 51 | USHORT ObjectTypeIndex; 52 | ULONG HandleAttributes; 53 | ULONG Reserved; 54 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; 55 | 56 | typedef struct _SYSTEM_HANDLE_INFORMATION_EX { 57 | ULONG_PTR NumberOfHandles; 58 | ULONG_PTR Reserved; 59 | SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; 60 | } SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; 61 | 62 | typedef enum _POOL_TYPE { 63 | NonPagedPool, 64 | PagedPool, 65 | NonPagedPoolMustSucceed, 66 | DontUseThisType, 67 | NonPagedPoolCacheAligned, 68 | PagedPoolCacheAligned, 69 | NonPagedPoolCacheAlignedMustS 70 | } POOL_TYPE, *PPOOL_TYPE; 71 | 72 | #ifndef __MINGW32__ 73 | typedef struct _OBJECT_TYPE_INFORMATION { 74 | UNICODE_STRING Name; 75 | ULONG TotalNumberOfObjects; 76 | ULONG TotalNumberOfHandles; 77 | ULONG TotalPagedPoolUsage; 78 | ULONG TotalNonPagedPoolUsage; 79 | ULONG TotalNamePoolUsage; 80 | ULONG TotalHandleTableUsage; 81 | ULONG HighWaterNumberOfObjects; 82 | ULONG HighWaterNumberOfHandles; 83 | ULONG HighWaterPagedPoolUsage; 84 | ULONG HighWaterNonPagedPoolUsage; 85 | ULONG HighWaterNamePoolUsage; 86 | ULONG HighWaterHandleTableUsage; 87 | ULONG InvalidAttributes; 88 | GENERIC_MAPPING GenericMapping; 89 | ULONG ValidAccess; 90 | BOOLEAN SecurityRequired; 91 | BOOLEAN MaintainHandleCount; 92 | USHORT MaintainTypeList; 93 | POOL_TYPE PoolType; 94 | ULONG PagedPoolUsage; 95 | ULONG NonPagedPoolUsage; 96 | } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; 97 | #endif 98 | 99 | PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName); 100 | VOID ps__get_open_files_init(void); 101 | SEXP ps__get_open_files(long pid, HANDLE processHandle); 102 | DWORD ps__NtQueryObject(void); 103 | DWORD WINAPI ps__NtQueryObjectThread(LPVOID lpvParam); 104 | SEXP ps__get_modules(HANDLE hProcess); 105 | SEXP ps__get_loadavg(double avg[3], SEXP counter_name); 106 | 107 | #endif // __PROCESS_HANDLES_H__ 108 | -------------------------------------------------------------------------------- /src/arch/windows/process_info.h: -------------------------------------------------------------------------------- 1 | 2 | #if !defined(__PROCESS_INFO_H) 3 | #define __PROCESS_INFO_H 4 | 5 | #include 6 | #include "ntextapi.h" 7 | 8 | #include 9 | 10 | DWORD* ps__get_pids(DWORD *numberOfReturnedPIDs); 11 | HANDLE ps__handle_from_pid(DWORD pid); 12 | HANDLE ps__handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess); 13 | int ps__get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, 14 | PVOID *retBuffer); 15 | 16 | int ps__assert_pid_exists(DWORD pid, char *err); 17 | int ps__assert_pid_not_exists(DWORD pid, char *err); 18 | 19 | SEXP ps__get_cmdline(DWORD pid); 20 | SEXP ps__get_cwd(DWORD pid); 21 | SEXP ps__get_environ(DWORD pid); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/arch/windows/wmi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. 3 | * Use of this source code is governed by a BSD-style license that can be 4 | * found in the LICENSE file. 5 | * 6 | * Functions related to the Windows Management Instrumentation API. 7 | */ 8 | 9 | #include "../../common.h" 10 | #include "../../windows.h" 11 | 12 | #include 13 | #include 14 | 15 | // We use an exponentially weighted moving average, just like Unix systems do 16 | // https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation 17 | // 18 | // These constants serve as the damping factor and are calculated with 19 | // 1 / exp(sampling interval in seconds / window size in seconds) 20 | // 21 | // This formula comes from linux's include/linux/sched/loadavg.h 22 | // https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23 23 | #define LOADAVG_FACTOR_1F 0.9200444146293232478931553241 24 | #define LOADAVG_FACTOR_5F 0.9834714538216174894737477501 25 | #define LOADAVG_FACTOR_15F 0.9944598480048967508795473394 26 | // The time interval in seconds between taking load counts, same as Linux 27 | #define SAMPLING_INTERVAL 5 28 | 29 | double load_avg_1m = 0; 30 | double load_avg_5m = 0; 31 | double load_avg_15m = 0; 32 | int load_avg_inited = 0; 33 | 34 | VOID CALLBACK LoadAvgCallback(PVOID hCounter, BOOLEAN timedOut) { 35 | PDH_FMT_COUNTERVALUE displayValue; 36 | double currentLoad; 37 | PDH_STATUS err; 38 | 39 | err = PdhGetFormattedCounterValue( 40 | (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &displayValue); 41 | // Skip updating the load if we can't get the value successfully 42 | if (err != ERROR_SUCCESS) { 43 | return; 44 | } 45 | currentLoad = displayValue.doubleValue; 46 | 47 | load_avg_1m = load_avg_1m * LOADAVG_FACTOR_1F + currentLoad * \ 48 | (1.0 - LOADAVG_FACTOR_1F); 49 | load_avg_5m = load_avg_5m * LOADAVG_FACTOR_5F + currentLoad * \ 50 | (1.0 - LOADAVG_FACTOR_5F); 51 | load_avg_15m = load_avg_15m * LOADAVG_FACTOR_15F + currentLoad * \ 52 | (1.0 - LOADAVG_FACTOR_15F); 53 | } 54 | 55 | 56 | void ps__init_loadavg_counter(SEXP counter_name) { 57 | WCHAR *szCounterPath = NULL; 58 | PDH_STATUS s; 59 | BOOL ret; 60 | HQUERY hQuery; 61 | HCOUNTER hCounter; 62 | HANDLE event; 63 | HANDLE waitHandle; 64 | 65 | ps__utf8_to_utf16(CHAR(STRING_ELT(counter_name, 0)), &szCounterPath); 66 | 67 | if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) { 68 | ps__set_error_from_windows_error(0); 69 | ps__throw_error(); 70 | } 71 | 72 | s = PdhAddCounterW(hQuery, szCounterPath, 0, &hCounter); 73 | if (s != ERROR_SUCCESS) { 74 | ps__set_error_from_windows_error(0); 75 | ps__throw_error(); 76 | } 77 | 78 | event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent"); 79 | if (event == NULL) { 80 | ps__set_error_from_windows_error(0); 81 | ps__throw_error(); 82 | } 83 | 84 | s = PdhCollectQueryDataEx(hQuery, SAMPLING_INTERVAL, event); 85 | if (s != ERROR_SUCCESS) { 86 | ps__set_error_from_windows_error(0); 87 | ps__throw_error(); 88 | } 89 | 90 | ret = RegisterWaitForSingleObject( 91 | &waitHandle, 92 | event, 93 | (WAITORTIMERCALLBACK)LoadAvgCallback, 94 | (PVOID) 95 | hCounter, 96 | INFINITE, 97 | WT_EXECUTEDEFAULT); 98 | 99 | if (ret == 0) { 100 | ps__set_error_from_windows_error(0); 101 | ps__throw_error(); 102 | } 103 | 104 | load_avg_inited = 1; 105 | } 106 | 107 | 108 | /* 109 | * Gets the emulated 1 minute, 5 minute and 15 minute load averages 110 | * (processor queue length) for the system. 111 | * `init_loadavg_counter` must be called before this function to engage the 112 | * mechanism that records load values. 113 | */ 114 | 115 | void ps__get_loadavg(double avg[3], SEXP counter_name) { 116 | if (!load_avg_inited) ps__init_loadavg_counter(counter_name); 117 | avg[0] = load_avg_1m; 118 | avg[1] = load_avg_5m; 119 | avg[2] = load_avg_15m; 120 | } 121 | -------------------------------------------------------------------------------- /src/cleancall.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEANCALL_H 2 | #define CLEANCALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // -------------------------------------------------------------------- 13 | // Internals 14 | // -------------------------------------------------------------------- 15 | 16 | typedef union {void* p; DL_FUNC fn;} fn_ptr; 17 | 18 | #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) 19 | SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); 20 | DL_FUNC R_ExternalPtrAddrFn(SEXP s); 21 | #endif 22 | 23 | // -------------------------------------------------------------------- 24 | // API for packages that embed cleancall 25 | // -------------------------------------------------------------------- 26 | 27 | // The R API does not have a setter for external function pointers 28 | SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); 29 | void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p); 30 | 31 | #define CLEANCALL_METHOD_RECORD \ 32 | {"cleancall_call", (DL_FUNC) &cleancall_call, 2} 33 | 34 | SEXP cleancall_call(SEXP args, SEXP env); 35 | void cleancall_init(void); 36 | 37 | // -------------------------------------------------------------------- 38 | // Public API 39 | // -------------------------------------------------------------------- 40 | 41 | #define R_CLEANCALL_SUPPORT 1 42 | 43 | SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data); 44 | void r_call_on_exit(void (*fn)(void* data), void* data); 45 | void r_call_on_early_exit(void (*fn)(void* data), void* data); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _GNU_SOURCE 3 | #define _GNU_SOURCE 1 4 | #endif 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "common.h" 11 | 12 | // Global vars. 13 | int PS__DEBUG = 0; 14 | int PS__TESTING = 0; 15 | 16 | /* 17 | * Enable testing mode. This has the same effect as setting PS__TESTING 18 | * env var. This dual method exists because updating os.environ on 19 | * Windows has no effect. Called on unit tests setup. 20 | */ 21 | void ps__set_testing(void) { 22 | PS__TESTING = 1; 23 | } 24 | 25 | 26 | /* 27 | * Print a debug message on stderr. No-op if PS__DEBUG env var is not set. 28 | */ 29 | void ps__debug(const char* format, ...) { 30 | va_list argptr; 31 | va_start(argptr, format); 32 | REprintf("psutil-debug> "); 33 | REvprintf(format, argptr); 34 | REprintf("\n"); 35 | va_end(argptr); 36 | } 37 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef R_PS_COMMON_H 3 | #define R_PS_COMMON_H 4 | 5 | #define R_USE_C99_IN_CXX 1 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ps-internal.h" 11 | 12 | /* ---------------------------------------------------------------------*/ 13 | /* Internals */ 14 | /* ---------------------------------------------------------------------*/ 15 | 16 | static R_INLINE SEXP ps_new_env(void) { 17 | SEXP env; 18 | #if R_VERSION >= R_Version(4, 1, 0) 19 | PROTECT(env = R_NewEnv(R_EmptyEnv, 1, 29)); 20 | #else 21 | PROTECT(env = Rf_allocSExp(ENVSXP)); 22 | SET_FRAME(env, R_NilValue); 23 | SET_ENCLOS(env, R_EmptyEnv); 24 | SET_HASHTAB(env, R_NilValue); 25 | SET_ATTRIB(env, R_NilValue); 26 | #endif 27 | UNPROTECT(1); 28 | return env; 29 | } 30 | 31 | extern int PS__TESTING; 32 | extern int PS__DEBUG; 33 | 34 | // a signaler for connections without an actual status 35 | static const int PS__CONN_NONE = 128; 36 | 37 | void ps__set_testing(void); 38 | void ps__debug(const char* format, ...); 39 | void R_init_ps(DllInfo *dll); 40 | 41 | #endif // PSUTIL_PSUTIL_COMMON_H 42 | -------------------------------------------------------------------------------- /src/install.libs.R: -------------------------------------------------------------------------------- 1 | progs <- if (WINDOWS) { 2 | c("px.exe", "interrupt.exe") 3 | } else { 4 | "px" 5 | } 6 | 7 | dest <- file.path(R_PACKAGE_DIR, paste0("bin", R_ARCH)) 8 | dir.create(dest, recursive = TRUE, showWarnings = FALSE) 9 | file.copy(progs, dest, overwrite = TRUE) 10 | 11 | files <- Sys.glob(paste0("*", SHLIB_EXT)) 12 | dest <- file.path(R_PACKAGE_DIR, paste0('libs', R_ARCH)) 13 | dir.create(dest, recursive = TRUE, showWarnings = FALSE) 14 | file.copy(files, dest, overwrite = TRUE) 15 | if (file.exists("symbols.rds")) { 16 | file.copy("symbols.rds", dest, overwrite = TRUE) 17 | } 18 | -------------------------------------------------------------------------------- /src/interrupt.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, const char **argv) { 7 | 8 | int ctrlbreak = 1; 9 | int pid; 10 | int ret; 11 | BOOL bret; 12 | 13 | if (argc == 1) return 1; 14 | ret = sscanf(argv[1], "%d", &pid); 15 | if (ret != 1) return 1; 16 | printf("Pid: %d\n", pid); 17 | 18 | if (argc == 3 && !strcmp(argv[2], "c")) ctrlbreak = 0; 19 | printf("Event: %s\n", ctrlbreak ? "ctrl+break" : "ctrl+c"); 20 | 21 | printf("Free console\n"); 22 | bret = FreeConsole(); 23 | if (!bret) return GetLastError(); 24 | 25 | printf("Attach console\n"); 26 | bret = AttachConsole(pid); 27 | if (!bret) return GetLastError(); 28 | 29 | printf("Set console ctrl handler\n"); 30 | SetConsoleCtrlHandler(NULL, TRUE); 31 | 32 | printf("Send event\n"); 33 | bret = GenerateConsoleCtrlEvent( 34 | ctrlbreak ? CTRL_BREAK_EVENT : CTRL_C_EVENT, 35 | 0); 36 | if (!bret) return GetLastError(); 37 | 38 | printf("Done\n"); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/linux.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _GNU_SOURCE 3 | #define _GNU_SOURCE 1 4 | #endif 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | #include "posix.h" 30 | 31 | int ps__read_file(const char *path, char **buffer, size_t buffer_size) { 32 | int fd = -1; 33 | ssize_t ret; 34 | char *ptr; 35 | size_t rem_size = buffer_size; 36 | 37 | *buffer = 0; 38 | 39 | fd = open(path, O_RDONLY); 40 | if (fd == -1) goto error; 41 | 42 | ptr = *buffer = R_alloc(buffer_size, 1); 43 | if (!*buffer) goto error; 44 | 45 | do { 46 | if (rem_size == 0) { 47 | *buffer = S_realloc(*buffer, buffer_size * 2, buffer_size, 1); 48 | if (!*buffer) goto error; 49 | ptr = *buffer + buffer_size; 50 | rem_size = buffer_size; 51 | buffer_size *= 2; 52 | } 53 | 54 | ret = read(fd, ptr, rem_size); 55 | if (ret == -1) goto error; 56 | 57 | ptr += ret; 58 | rem_size -= ret; 59 | } while (ret > 0); 60 | 61 | close(fd); 62 | 63 | return buffer_size - rem_size; 64 | 65 | error: 66 | if (fd >= 0) close(fd); 67 | *buffer = 0; 68 | return -1; 69 | } 70 | 71 | SEXP ps__inet_ntop(SEXP raw, SEXP fam) { 72 | char dst[INET6_ADDRSTRLEN]; 73 | int af = INTEGER(fam)[0]; 74 | const char *ret = inet_ntop(af, RAW(raw), dst, INET6_ADDRSTRLEN); 75 | if (!ret) { 76 | return R_NilValue; 77 | } else { 78 | return mkString(dst); 79 | } 80 | } 81 | 82 | SEXP ps__define_tcp_statuses(void) { 83 | SEXP result, names; 84 | 85 | PROTECT(result = ps__build_string("01", "02", "03", "04", "05", "06", 86 | "07", "08", "09", "0A", "0B", "0C", NULL)); 87 | PROTECT(names = ps__build_string("CONN_ESTABLISHED", 88 | "CONN_SYN_SENT", 89 | "CONN_SYN_RECV", 90 | "CONN_FIN_WAIT_1", 91 | "CONN_FIN_WAIT_2", 92 | "CONN_TIME_WAIT", 93 | "CONN_CLOSE", 94 | "CONN_CLOSE_WAIT", 95 | "CONN_LAST_ACK", 96 | "CONN_LISTEN", 97 | "CONN_CLOSING", 98 | "PS__CONN_NONE", NULL)); 99 | 100 | setAttrib(result, R_NamesSymbol, names); 101 | UNPROTECT(2); 102 | return result; 103 | } 104 | 105 | SEXP ps__init(SEXP psenv, SEXP constenv) { 106 | 107 | SEXP sig, err, tcp, af, st; 108 | 109 | /* Signals */ 110 | PROTECT(sig = ps__define_signals()); 111 | defineVar(install("signals"), sig, constenv); 112 | 113 | /* errno values */ 114 | PROTECT(err = ps__define_errno()); 115 | defineVar(install("errno"), err, constenv); 116 | 117 | /* Connection statuses */ 118 | PROTECT(tcp = ps__define_tcp_statuses()); 119 | defineVar(install("tcp_statuses"), tcp, constenv); 120 | 121 | /* Socket address families */ 122 | PROTECT(af = ps__define_socket_address_families()); 123 | defineVar(install("address_families"), af, constenv); 124 | 125 | /* Socket address families */ 126 | PROTECT(st = ps__define_socket_types()); 127 | defineVar(install("socket_types"), st, constenv); 128 | 129 | UNPROTECT(5); 130 | return R_NilValue; 131 | } 132 | -------------------------------------------------------------------------------- /src/macos.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _GNU_SOURCE 3 | #define _GNU_SOURCE 1 4 | #endif 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "common.h" 41 | #include "posix.h" 42 | #include "arch/macos/process_info.h" 43 | 44 | 45 | #define PS__TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) 46 | 47 | /* 48 | * Return an integer vector of all the PIDs running on the system. 49 | */ 50 | SEXP ps__pids(void) { 51 | kinfo_proc *proclist = NULL; 52 | kinfo_proc *orig_address = NULL; 53 | size_t num_processes; 54 | size_t idx; 55 | SEXP retlist = R_NilValue; 56 | 57 | if (ps__get_proc_list(&proclist, &num_processes) != 0) { 58 | if (errno != 0) { 59 | ps__set_error_from_errno(); 60 | } else { 61 | ps__set_error("failed to retrieve process list"); 62 | } 63 | goto error; 64 | } 65 | 66 | retlist = PROTECT(allocVector(INTSXP, num_processes)); 67 | 68 | if (num_processes > 0) { 69 | // save the address of proclist so we can free it later 70 | orig_address = proclist; 71 | for (idx = 0; idx < num_processes; idx++) { 72 | INTEGER(retlist)[idx] = proclist->kp_proc.p_pid; 73 | proclist++; 74 | } 75 | free(orig_address); 76 | } 77 | 78 | UNPROTECT(1); 79 | return retlist; 80 | 81 | error: 82 | if (orig_address != NULL) free(orig_address); 83 | ps__throw_error(); 84 | return R_NilValue; 85 | } 86 | 87 | SEXP ps__define_tcp_statuses(void) { 88 | SEXP result, names; 89 | 90 | PROTECT(result = allocVector(INTSXP, 12)); 91 | PROTECT(names = allocVector(STRSXP, 12)); 92 | 93 | INTEGER(result)[0] = TCPS_CLOSED; 94 | SET_STRING_ELT(names, 0, mkChar("CONN_CLOSE")); 95 | INTEGER(result)[1] = TCPS_CLOSING; 96 | SET_STRING_ELT(names, 1, mkChar("CONN_CLOSING")); 97 | INTEGER(result)[2] = TCPS_CLOSE_WAIT; 98 | SET_STRING_ELT(names, 2, mkChar("CONN_CLOSE_WAIT")); 99 | INTEGER(result)[3] = TCPS_LISTEN; 100 | SET_STRING_ELT(names, 3, mkChar("CONN_LISTEN")); 101 | INTEGER(result)[4] = TCPS_ESTABLISHED; 102 | SET_STRING_ELT(names, 4, mkChar("CONN_ESTABLISHED")); 103 | INTEGER(result)[5] = TCPS_SYN_SENT; 104 | SET_STRING_ELT(names, 5, mkChar("CONN_SYN_SENT")); 105 | INTEGER(result)[6] = TCPS_SYN_RECEIVED; 106 | SET_STRING_ELT(names, 6, mkChar("CONN_SYN_RECV")); 107 | INTEGER(result)[7] = TCPS_FIN_WAIT_1; 108 | SET_STRING_ELT(names, 7, mkChar("CONN_FIN_WAIT_1")); 109 | INTEGER(result)[8] = TCPS_FIN_WAIT_2; 110 | SET_STRING_ELT(names, 8, mkChar("CONN_FIN_WAIT_2")); 111 | INTEGER(result)[9] = TCPS_LAST_ACK; 112 | SET_STRING_ELT(names, 9, mkChar("CONN_LAST_ACK")); 113 | INTEGER(result)[10] = TCPS_TIME_WAIT; 114 | SET_STRING_ELT(names, 10, mkChar("CONN_TIME_WAIT")); 115 | INTEGER(result)[11] = PS__CONN_NONE; 116 | SET_STRING_ELT(names, 11, mkChar("PS__CONN_NONE")); 117 | 118 | setAttrib(result, R_NamesSymbol, names); 119 | UNPROTECT(2); 120 | return result; 121 | } 122 | 123 | SEXP ps__init(SEXP psenv, SEXP constenv) { 124 | 125 | /* Signals */ 126 | defineVar(install("signals"), ps__define_signals(), constenv); 127 | 128 | /* errno values */ 129 | defineVar(install("errno"), ps__define_errno(), constenv); 130 | 131 | /* Connection statuses */ 132 | defineVar(install("tcp_statuses"), ps__define_tcp_statuses(), constenv); 133 | 134 | /* Socket address families */ 135 | defineVar(install("address_families"), 136 | ps__define_socket_address_families(), constenv); 137 | 138 | /* Socket address families */ 139 | defineVar(install("socket_types"), ps__define_socket_types(), constenv); 140 | 141 | return R_NilValue; 142 | } 143 | -------------------------------------------------------------------------------- /src/posix.h: -------------------------------------------------------------------------------- 1 | 2 | int ps__pid_exists(long pid); 3 | void ps__raise_for_pid(long pid, char *msg); 4 | -------------------------------------------------------------------------------- /src/ps-internal.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef R_PS_INTERNAL_H 3 | #define R_PS_INTERNAL_H 4 | 5 | #include "config.h" 6 | #include "ps.h" 7 | 8 | #define PROCESSX_INTERRUPT_INTERVAL 200 9 | 10 | #ifdef PS__MACOS 11 | 12 | #include 13 | 14 | typedef struct { 15 | pid_t pid; 16 | double create_time; 17 | int gone; 18 | } ps_handle_t; 19 | 20 | #endif 21 | 22 | #ifdef PS__LINUX 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | typedef struct { 29 | pid_t pid; 30 | double create_time; 31 | int gone; 32 | } ps_handle_t; 33 | 34 | #endif 35 | 36 | #ifdef PS__WINDOWS 37 | 38 | #include 39 | 40 | typedef struct { 41 | DWORD pid; 42 | double create_time; 43 | int gone; 44 | FILETIME wtime; 45 | } ps_handle_t; 46 | 47 | #endif 48 | 49 | #ifndef PS__MACOS 50 | #ifndef PS__LINUX 51 | #ifndef PS__WINDOWS 52 | 53 | typedef struct { 54 | int pid; 55 | double create_time; 56 | } ps_handle_t; 57 | 58 | #endif 59 | #endif 60 | #endif 61 | 62 | /* Internal utilities */ 63 | 64 | SEXP psll__is_running(ps_handle_t *handle); 65 | 66 | SEXP ps__get_pw_uid(SEXP r_uid); 67 | SEXP ps__define_signals(void); 68 | SEXP ps__define_errno(void); 69 | SEXP ps__define_socket_address_families(void); 70 | SEXP ps__define_socket_types(void); 71 | 72 | #define PS_MAYBE 0 73 | #define PS_YEAH 1 74 | #define PS_NOPE 2 75 | 76 | extern int ps_pidfd_open_support; 77 | 78 | /* Errors */ 79 | 80 | extern SEXP ps__last_error; 81 | 82 | void ps__protect_free_finalizer(SEXP ptr); 83 | 84 | #define PROTECT_PTR(ptr) do { \ 85 | SEXP x = PROTECT(R_MakeExternalPtr(ptr, R_NilValue, R_NilValue)); \ 86 | R_RegisterCFinalizerEx(x, ps__protect_free_finalizer, 1); \ 87 | } while (0) 88 | 89 | void *ps__set_error(const char *msg, ...); 90 | void *ps__set_error_from_errno(void); 91 | SEXP ps__throw_error(void); 92 | 93 | void *ps__access_denied(const char *msg); 94 | void *ps__access_denied_pid(long pid, const char *msg); 95 | void *ps__no_such_process(long pid, const char *name); 96 | void *ps__zombie_process(long pid); 97 | void *ps__no_memory(const char *msg); 98 | void *ps__not_implemented(const char *what); 99 | void ps__check_for_zombie(ps_handle_t *handle, int err); 100 | 101 | void *ps__set_error_from_windows_error(long err); 102 | 103 | /* Build SEXP values */ 104 | 105 | SEXP ps__build_string(const char *str, ...); 106 | SEXP ps__build_list(const char *template, ...); 107 | SEXP ps__build_named_list(const char *template, ...); 108 | 109 | /* String conversions */ 110 | 111 | SEXP ps__str_to_utf8(const char *str); 112 | SEXP ps__str_to_utf8_size(const char *str, size_t size); 113 | 114 | #ifdef PS__WINDOWS 115 | SEXP ps__utf16_to_rawsxp(const WCHAR* ws, int size); 116 | SEXP ps__utf16_to_charsxp(const WCHAR* ws, int size); 117 | SEXP ps__utf16_to_strsxp(const WCHAR* ws, int size); 118 | int ps__utf8_to_utf16(const char* s, WCHAR** ws_ptr); 119 | #endif 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /src/ps.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef R_PS_H 3 | #define R_PS_H 4 | 5 | #define R_USE_C99_IN_CXX 1 6 | #include 7 | 8 | /* API to be used from R */ 9 | 10 | /* ps_handle class */ 11 | 12 | SEXP psll_handle(SEXP pid, SEXP time); 13 | 14 | SEXP psll_pid(SEXP p); 15 | SEXP psll_create_time(SEXP p); 16 | 17 | SEXP psll_format(SEXP p); 18 | SEXP psll_parent(SEXP p); 19 | SEXP psll_ppid(SEXP p); 20 | SEXP psll_is_running(SEXP p); 21 | SEXP psll_name(SEXP p); 22 | SEXP psll_exe(SEXP p); 23 | SEXP psll_cmdline(SEXP p); 24 | SEXP psll_status(SEXP p); 25 | SEXP psll_username(SEXP p); 26 | SEXP psll_cwd(SEXP p); 27 | SEXP psll_uids(SEXP p); 28 | SEXP psll_gids(SEXP p); 29 | SEXP psll_terminal(SEXP p); 30 | SEXP psll_environ(SEXP p); 31 | SEXP psll_num_threads(SEXP p); 32 | SEXP psll_cpu_times(SEXP p); 33 | SEXP psll_memory_info(SEXP p); 34 | SEXP psll_memory_uss(SEXP p); 35 | SEXP psll_memory_maxrss(SEXP p); 36 | SEXP psll_send_signal(SEXP p, SEXP sig); 37 | SEXP psll_suspend(SEXP p); 38 | SEXP psll_resume(SEXP p); 39 | SEXP psll_terminate(SEXP p); 40 | SEXP psll_kill(SEXP p, SEXP grace); 41 | SEXP psll_num_fds(SEXP p); 42 | SEXP psll_open_files(SEXP p); 43 | SEXP psll_interrupt(SEXP p, SEXP ctrlc, SEXP interrupt_path); 44 | SEXP psll_connections(SEXP p); 45 | SEXP psll_get_nice(SEXP p); 46 | SEXP psll_set_nice(SEXP p, SEXP value); 47 | SEXP psll_dlls(SEXP p); 48 | SEXP psll_get_cpu_aff(SEXP p); 49 | SEXP psll_set_cpu_aff(SEXP p, SEXP affinity); 50 | SEXP psll_wait(SEXP p, SEXP timeout); 51 | 52 | /* System API */ 53 | 54 | SEXP ps__os_type(void); 55 | SEXP ps__pids(void); 56 | SEXP ps__boot_time(void); 57 | SEXP ps__cpu_count_logical(void); 58 | SEXP ps__cpu_count_physical(void); 59 | SEXP ps__system_cpu_times(void); 60 | SEXP ps__users(void); 61 | SEXP ps__tty_size(void); 62 | SEXP ps__disk_partitions(SEXP all); 63 | SEXP ps__disk_usage(SEXP paths); 64 | SEXP ps__disk_io_counters(void); 65 | SEXP ps__fs_info(SEXP path, SEXP abspath, SEXP mps); 66 | SEXP ps__system_memory(void); 67 | SEXP ps__system_swap(void); 68 | SEXP ps__loadavg(SEXP counter_name); 69 | SEXP ps__list_apps(void); 70 | SEXP ps__stat(SEXP path, SEXP follow); 71 | SEXP ps__mount_point(SEXP paths); 72 | 73 | /* Generic utils used from R */ 74 | 75 | SEXP ps__init(SEXP psenv, SEXP constenv); 76 | SEXP ps__find_if_env(SEXP marker, SEXP after, SEXP pid); 77 | SEXP ps__inet_ntop(SEXP raw, SEXP fam); 78 | SEXP ps__memory_maps(SEXP p); 79 | 80 | SEXP psp__zombie(void); 81 | SEXP psp__waitpid(SEXP pid); 82 | SEXP psp__pid_exists(SEXP r_pid); 83 | SEXP psp__stat_st_rdev(SEXP files); 84 | 85 | SEXP psw__realpath(SEXP path); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/windows.h: -------------------------------------------------------------------------------- 1 | 2 | /* Non-throwing internal API */ 3 | 4 | SEXP ps__exe(DWORD pid); 5 | SEXP ps__name(DWORD pid); 6 | SEXP ps__ppid(DWORD pid); 7 | SEXP ps__proc_name(DWORD pid); 8 | SEXP ps__get_cmdline(DWORD pid); 9 | SEXP ps__get_cwd(DWORD pid); 10 | SEXP ps__get_environ(DWORD pid); 11 | SEXP ps__proc_num_threads(DWORD pid); 12 | SEXP ps__proc_cpu_times(DWORD pid); 13 | SEXP ps__proc_info(DWORD pid); 14 | SEXP ps__proc_username(DWORD pid); 15 | SEXP ps__proc_suspend(DWORD pid); 16 | SEXP ps__proc_resume(DWORD pid); 17 | SEXP ps__proc_kill(DWORD pid); 18 | 19 | double ps__filetime_to_unix(FILETIME ft); 20 | SEXP ps__convert_dos_path(WCHAR *wstr); 21 | void PS__CHECK_HANDLE(ps_handle_t *handle); 22 | 23 | #define MALLOC_ZERO(x) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)) 24 | #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) 25 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(ps) 3 | 4 | if ( 5 | ps::ps_is_supported() && 6 | Sys.getenv("R_COVR", "") != "true" && 7 | Sys.getenv("NOT_CRAN") != "" 8 | ) { 9 | reporter <- ps::CleanupReporter(testthat::SummaryReporter)$new() 10 | } else { 11 | reporter <- "summary" 12 | } 13 | 14 | if (ps_is_supported() && Sys.getenv("NOT_CRAN") != "") { 15 | test_check("ps", reporter = reporter) 16 | } 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/common.md: -------------------------------------------------------------------------------- 1 | # kill 2 2 | 3 | Code 4 | ps_kill(list(ph5, ph6)) 5 | Condition 6 | Error: 7 | ! preventing sending KILL signal to process with PID 0 as it would affect every process in the process group of the calling process (Sys.getpid()) instead of PID 0 8 | 9 | --- 10 | 11 | Code 12 | ps_kill(list(ph7, ph8, ph9)) 13 | Condition 14 | Error: 15 | ! Failed to kill some processes: 1 (launchd) 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/fixtures/cleanup-error/test-cleanup-error.R: -------------------------------------------------------------------------------- 1 | # https://github.com/r-lib/ps/issues/163 2 | test_that("errors still cause a failure", { 3 | stop("oops") 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/helpers.R: -------------------------------------------------------------------------------- 1 | format_regexp <- function() { 2 | " PID=[0-9]+, NAME=.*, AT=" 3 | } 4 | 5 | parse_ps <- function(args) { 6 | out <- processx::run("ps", args)$stdout 7 | sub(" *$", "", strsplit(out, "\n")[[1]][[2]]) 8 | } 9 | 10 | parse_time <- function(x) { 11 | x <- utils::tail(c(0, 0, 0, as.numeric(strsplit(x, ":")[[1]])), 3) 12 | x[1] * 60 * 60 + x[2] * 60 + x[3] 13 | } 14 | 15 | wait_for_status <- function(ps, status, timeout = 5) { 16 | limit <- Sys.time() + timeout 17 | while (ps_status(ps) != status && Sys.time() < limit) Sys.sleep(0.05) 18 | } 19 | 20 | px <- function() get_tool("px") 21 | 22 | skip_in_rstudio <- function() { 23 | if (Sys.getenv("RSTUDIO") != "") skip("Cannot test in RStudio") 24 | } 25 | 26 | has_processx <- function() { 27 | requireNamespace("processx", quietly = TRUE) && 28 | package_version(getNamespaceVersion("processx")) >= "3.1.0.9005" 29 | } 30 | 31 | skip_if_no_processx <- function() { 32 | if (!has_processx()) skip("Needs processx >= 3.1.0.9005 to run") 33 | } 34 | 35 | skip_without_program <- function(prog) { 36 | if (Sys.which(prog) == "") skip(paste(prog, "is not available")) 37 | } 38 | 39 | have_ipv6_support <- function() { 40 | ps_os_type()[["WINDOWS"]] || 41 | !is.null(ps_env$constants$address_families$AF_INET6) 42 | } 43 | 44 | skip_without_ipv6 <- function() { 45 | if (!have_ipv6_support()) skip("Needs IPv6") 46 | } 47 | 48 | ipv6_url <- function() { 49 | paste0("https://", ipv6_host()) 50 | } 51 | 52 | ipv6_host <- function() { 53 | "ipv6.test-ipv6.com" 54 | } 55 | 56 | have_ipv6_connection <- local({ 57 | ok <- NULL 58 | myurl <- NULL 59 | function(url = ipv6_url()) { 60 | if (is.null(ok) || myurl != url) { 61 | myurl <<- url 62 | opt <- options(warn = 2) 63 | on.exit(options(opt), add = TRUE) 64 | tryCatch( 65 | { 66 | cx <- curl::curl(url) 67 | open(cx) 68 | ok <<- TRUE 69 | }, 70 | error = function(x) ok <<- FALSE, 71 | finally = close(cx) 72 | ) 73 | } 74 | ok 75 | } 76 | }) 77 | 78 | skip_without_ipv6_connection <- function() { 79 | if (!have_ipv6_connection()) skip("Needs working IPv6 connection") 80 | } 81 | 82 | wait_for_string <- function(proc, string, timeout) { 83 | deadline <- Sys.time() + as.difftime(timeout / 1000, units = "secs") 84 | str <- "" 85 | repeat { 86 | left <- max(as.double(deadline - Sys.time(), units = "secs"), 0) 87 | pr <- processx::poll(list(proc), as.integer(left * 1000)) 88 | str <- paste(str, proc$read_error()) 89 | if (grepl(string, str)) return() 90 | if (proc$has_output_connection()) read_output() 91 | if (deadline < Sys.time()) stop("Cannot start proces") 92 | if (!proc$is_alive()) stop("Cannot start process") 93 | } 94 | } 95 | 96 | ## This is not perfect, e.g. we don't check that the numbers are <255, 97 | ## but will do for our purposes 98 | 99 | is_ipv4_address <- function(x) { 100 | grepl("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$", x) 101 | } 102 | 103 | cleanup_process <- function(p) { 104 | tryCatch(close(p$get_input_connection()), error = function(x) x) 105 | tryCatch(close(p$get_output_connection()), error = function(x) x) 106 | tryCatch(close(p$get_error_connection()), error = function(x) x) 107 | tryCatch(close(p$get_poll_connection()), error = function(x) x) 108 | tryCatch(p$kill(), error = function(x) x) 109 | } 110 | 111 | httpbin <- webfakes::new_app_process( 112 | webfakes::httpbin_app(), 113 | opts = webfakes::server_opts(num_threads = 6) 114 | ) 115 | -------------------------------------------------------------------------------- /tests/testthat/test-disk.R: -------------------------------------------------------------------------------- 1 | test_that("ps_fs_info", { 2 | skip_on_os("windows") 3 | 4 | # just test that it runs 5 | expect_silent( 6 | ps_fs_info(c("/", "~", ".")) 7 | ) 8 | }) 9 | 10 | test_that("disk_io", { 11 | result <- ps_disk_io_counters() 12 | 13 | # Check structure 14 | expect_named( 15 | result, 16 | c( 17 | "read_bytes", 18 | "write_bytes", 19 | "read_count", 20 | "write_count", 21 | "read_merged_count", 22 | "read_time", 23 | "write_merged_count", 24 | "write_time", 25 | "busy_time", 26 | "name" 27 | ), 28 | ignore.order = TRUE 29 | ) 30 | expect_type(result, "list") 31 | expect_s3_class(result, "data.frame") 32 | }) 33 | -------------------------------------------------------------------------------- /tests/testthat/test-finished.R: -------------------------------------------------------------------------------- 1 | test_that("process already finished", { 2 | skip_on_cran() 3 | px <- processx::process$new(px(), c("sleep", "5")) 4 | on.exit(px$kill(), add = TRUE) 5 | pid <- px$get_pid() 6 | p <- ps_handle(pid) 7 | ct <- ps_create_time(p) 8 | 9 | px$kill() 10 | 11 | expect_false(px$is_alive()) 12 | if (ps_os_type()[["POSIX"]]) { 13 | expect_equal(px$get_exit_status(), -9) 14 | } 15 | 16 | expect_match(format(p), format_regexp()) 17 | expect_output(print(p), format_regexp()) 18 | 19 | expect_equal(ps_pid(p), pid) 20 | if (has_processx()) expect_equal(ps_create_time(p), ct) 21 | expect_false(ps_is_running(p)) 22 | 23 | chk <- function(expr) { 24 | err <- tryCatch(expr, error = function(e) e) 25 | expect_s3_class(err, "no_such_process") 26 | expect_s3_class(err, "ps_error") 27 | expect_equal(err$pid, pid) 28 | } 29 | 30 | ## All these error out with "no_such_process" 31 | chk(ps_status(p)) 32 | chk(ps_ppid(p)) 33 | chk(ps_parent(p)) 34 | chk(ps_name(p)) 35 | if (ps_os_type()[["POSIX"]]) chk(ps_uids(p)) 36 | chk(ps_username(p)) 37 | if (ps_os_type()[["POSIX"]]) chk(ps_gids(p)) 38 | chk(ps_terminal(p)) 39 | 40 | if (ps_os_type()[["POSIX"]]) chk(ps_send_signal(p, signals()$SIGINT)) 41 | chk(ps_suspend(p)) 42 | chk(ps_resume(p)) 43 | if (ps_os_type()[["POSIX"]]) chk(ps_terminate(p)) 44 | 45 | ## kill will just work if the process has finished already 46 | expect_equal(ps_kill(p), "dead") 47 | 48 | chk(ps_exe(p)) 49 | chk(ps_cmdline(p)) 50 | chk(ps_environ(p)) 51 | chk(ps_cwd(p)) 52 | chk(ps_memory_info(p)) 53 | chk(ps_cpu_times(p)) 54 | chk(ps_num_threads(p)) 55 | chk(ps_children(p)) 56 | chk(ps_num_fds(p)) 57 | chk(ps_open_files(p)) 58 | chk(ps_connections(p)) 59 | }) 60 | -------------------------------------------------------------------------------- /tests/testthat/test-linux.R: -------------------------------------------------------------------------------- 1 | if (!ps_os_type()[["LINUX"]]) return() 2 | 3 | test_that("status", { 4 | ## Argument check 5 | expect_error(ps_status(123), class = "invalid_argument") 6 | 7 | p1 <- processx::process$new("sleep", "10") 8 | on.exit(p1$kill(), add = TRUE) 9 | ps <- ps_handle(p1$get_pid()) 10 | expect_true(ps_is_running(ps)) 11 | 12 | wait_for_status(ps, "sleeping") 13 | expect_equal(ps_status(ps), "sleeping") 14 | ps_suspend(ps) 15 | wait_for_status(ps, "stopped") 16 | expect_equal(ps_status(ps), "stopped") 17 | ps_resume(ps) 18 | wait_for_status(ps, "sleeping") 19 | expect_equal(ps_status(ps), "sleeping") 20 | ## TODO: rest? 21 | }) 22 | 23 | ## TODO: cpu_times ??? We apparently cannot get them from ps 24 | 25 | test_that("memory_info", { 26 | ## Argument check 27 | expect_error(ps_memory_info(123), class = "invalid_argument") 28 | 29 | skip_on_cran() 30 | 31 | p1 <- processx::process$new("ls", c("-lR", "/")) 32 | on.exit(p1$kill(), add = TRUE) 33 | ps <- ps_handle(p1$get_pid()) 34 | 35 | Sys.sleep(0.2) 36 | ps_suspend(ps) 37 | mem <- ps_memory_info(ps) 38 | mem2 <- scan( 39 | sprintf("/proc/%d/statm", ps_pid(ps)), 40 | what = integer(), 41 | quiet = TRUE 42 | ) 43 | page_size <- as.integer(system2("getconf", "PAGESIZE", stdout = TRUE)) 44 | 45 | expect_equal(mem[["vms"]], mem2[[1]] * page_size) 46 | expect_equal(mem[["rss"]], mem2[[2]] * page_size) 47 | }) 48 | -------------------------------------------------------------------------------- /tests/testthat/test-macos.R: -------------------------------------------------------------------------------- 1 | if (!ps_os_type()[["MACOS"]]) return() 2 | 3 | test_that("status", { 4 | ## Argument check 5 | skip_on_cran() 6 | expect_error(ps_status(123), class = "invalid_argument") 7 | 8 | p1 <- processx::process$new("sleep", "10") 9 | on.exit(cleanup_process(p1), add = TRUE) 10 | ps <- ps_handle(p1$get_pid()) 11 | expect_true(ps_is_running(ps)) 12 | 13 | expect_equal(ps_status(), "running") 14 | expect_equal(ps_status(ps), "sleeping") 15 | ps_suspend(ps) 16 | expect_equal(ps_status(ps), "stopped") 17 | ps_resume(ps) 18 | expect_equal(ps_status(ps), "sleeping") 19 | ## TODO: can't easily test 'idle' 20 | }) 21 | 22 | test_that("cpu_times", { 23 | skip_on_cran() 24 | 25 | ## Argument check 26 | expect_error(ps_cpu_times(123), class = "invalid_argument") 27 | 28 | p1 <- processx::process$new("ls", c("-lR", "/")) 29 | on.exit(cleanup_process(p1), add = TRUE) 30 | ps <- ps_handle(p1$get_pid()) 31 | 32 | Sys.sleep(0.2) 33 | ps_suspend(ps) 34 | ct <- ps_cpu_times(ps) 35 | ps2_user <- parse_time(parse_ps(c("-o", "utime", "-p", ps_pid(ps)))) 36 | ps2_total <- parse_time(parse_ps(c("-o", "time", "-p", ps_pid(ps)))) 37 | 38 | expect_true(abs(round(ct[["user"]], 2) - ps2_user) < 0.2) 39 | expect_true(abs(round(ct[["system"]], 2) - (ps2_total - ps2_user)) < 0.2) 40 | }) 41 | 42 | test_that("memory_info", { 43 | skip_on_cran() 44 | 45 | ## Argument check 46 | expect_error(ps_memory_info(123), class = "invalid_argument") 47 | 48 | p1 <- processx::process$new("ls", c("-lR", "/")) 49 | on.exit(cleanup_process(p1), add = TRUE) 50 | ps <- ps_handle(p1$get_pid()) 51 | 52 | Sys.sleep(0.2) 53 | ps_suspend(ps) 54 | mem <- ps_memory_info(ps) 55 | ps2_rss <- as.numeric(parse_ps(c("-o", "rss", "-p", ps_pid(ps)))) 56 | ps2_vms <- as.numeric(parse_ps(c("-o", "vsize", "-p", ps_pid(ps)))) 57 | 58 | expect_equal(mem[["rss"]] / 1024, ps2_rss, tolerance = 10) 59 | expect_equal(mem[["vms"]] / 1024, ps2_vms, tolerance = 10) 60 | }) 61 | -------------------------------------------------------------------------------- /tests/testthat/test-pid-reuse.R: -------------------------------------------------------------------------------- 1 | test_that("pid reuse", { 2 | ## This is simulated, because it is quite some work to force a pid 3 | ## reuse on some systems. So we create a handle with the pid of a 4 | ## running process, but wrong (earlier) create time stamp. 5 | 6 | z <- processx::process$new(px(), c("sleep", "600")) 7 | on.exit(z$kill(), add = TRUE) 8 | zpid <- z$get_pid() 9 | 10 | ctime <- Sys.time() - 60 11 | attr(ctime, "tzone") <- "GMT" 12 | p <- ps_handle(zpid, ctime) 13 | 14 | expect_match(format(p), format_regexp()) 15 | expect_output(print(p), format_regexp()) 16 | 17 | expect_equal(ps_pid(p), zpid) 18 | expect_equal(ps_create_time(p), ctime) 19 | expect_false(ps_is_running(p)) 20 | 21 | chk <- function(expr) { 22 | err <- tryCatch(expr, error = function(e) e) 23 | expect_s3_class(err, "no_such_process") 24 | expect_s3_class(err, "ps_error") 25 | expect_equal(err$pid, zpid) 26 | } 27 | 28 | ## All these error out with "no_such_process" 29 | chk(ps_status(p)) 30 | chk(ps_ppid(p)) 31 | chk(ps_parent(p)) 32 | chk(ps_name(p)) 33 | if (ps_os_type()[["POSIX"]]) chk(ps_uids(p)) 34 | chk(ps_username(p)) 35 | if (ps_os_type()[["POSIX"]]) chk(ps_gids(p)) 36 | chk(ps_terminal(p)) 37 | 38 | if (ps_os_type()[["POSIX"]]) chk(ps_send_signal(p, signals()$SIGINT)) 39 | chk(ps_suspend(p)) 40 | chk(ps_resume(p)) 41 | if (ps_os_type()[["POSIX"]]) chk(ps_terminate(p)) 42 | 43 | # kill will be still OK, the original process is already dead 44 | expect_equal(ps_kill(p), "dead") 45 | 46 | chk(ps_exe(p)) 47 | chk(ps_cmdline(p)) 48 | chk(ps_environ(p)) 49 | chk(ps_cwd(p)) 50 | chk(ps_memory_info(p)) 51 | chk(ps_cpu_times(p)) 52 | chk(ps_num_threads(p)) 53 | chk(ps_num_fds(p)) 54 | chk(ps_open_files(p)) 55 | chk(ps_connections(p)) 56 | }) 57 | -------------------------------------------------------------------------------- /tests/testthat/test-posix-zombie.R: -------------------------------------------------------------------------------- 1 | if (!ps_os_type()[["POSIX"]]) return() 2 | 3 | test_that("zombie api", { 4 | zpid <- zombie() 5 | on.exit(waitpid(zpid), add = TRUE) 6 | p <- ps_handle(zpid) 7 | me <- ps_handle() 8 | 9 | expect_match(format(p), format_regexp()) 10 | expect_output(print(p), format_regexp()) 11 | 12 | expect_equal(ps_pid(p), zpid) 13 | expect_true(ps_create_time(p) > ps_create_time(me)) 14 | expect_true(ps_is_running(p)) 15 | expect_equal(ps_status(p), "zombie") 16 | expect_equal(ps_ppid(p), Sys.getpid()) 17 | expect_equal(ps_pid(ps_parent(p)), Sys.getpid()) 18 | expect_equal(ps_name(p), ps_name(me)) 19 | expect_identical(ps_uids(p), ps_uids(me)) 20 | expect_identical(ps_username(p), ps_username(me)) 21 | expect_identical(ps_gids(p), ps_gids(me)) 22 | expect_identical(ps_terminal(p), ps_terminal(me)) 23 | expect_silent(ps_children(p)) 24 | 25 | ## You can still send signals if you like 26 | expect_silent(ps_send_signal(p, signals()$SIGINT)) 27 | expect_equal(ps_status(p), "zombie") 28 | expect_silent(ps_suspend(p)) 29 | expect_equal(ps_status(p), "zombie") 30 | expect_silent(ps_resume(p)) 31 | expect_equal(ps_status(p), "zombie") 32 | expect_silent(ps_terminate(p)) 33 | expect_equal(ps_status(p), "zombie") 34 | expect_silent(ps_kill(p)) 35 | expect_equal(ps_status(p), "zombie") 36 | 37 | chk <- function(expr) { 38 | err <- tryCatch(expr, error = function(e) e) 39 | expect_s3_class(err, "zombie_process") 40 | expect_s3_class(err, "ps_error") 41 | expect_equal(err$pid, zpid) 42 | } 43 | 44 | ## These raise zombie_process errors 45 | chk(ps_exe(p)) 46 | chk(ps_cmdline(p)) 47 | chk(ps_environ(p)) 48 | chk(ps_cwd(p)) 49 | chk(ps_memory_info(p)) 50 | chk(ps_cpu_times(p)) 51 | chk(ps_num_threads(p)) 52 | chk(ps_num_fds(p)) 53 | chk(ps_open_files(p)) 54 | chk(ps_connections(p)) 55 | chk(ps_get_nice(p)) 56 | chk(ps_set_nice(p, 20L)) 57 | if (ps_os_type()[["MACOS"]]) { 58 | chk(.Call(psll_memory_uss, p)) 59 | } else if (ps_os_type()[["LINUX"]]) { 60 | chk(.Call(ps__memory_maps, p)) 61 | } 62 | }) 63 | -------------------------------------------------------------------------------- /tests/testthat/test-posix.R: -------------------------------------------------------------------------------- 1 | if (!ps_os_type()[["POSIX"]]) return() 2 | 3 | test_that("is_running", { 4 | ## Zombie is running 5 | zpid <- zombie() 6 | on.exit(waitpid(zpid), add = TRUE) 7 | ps <- ps_handle(zpid) 8 | expect_true(ps_is_running(ps)) 9 | }) 10 | 11 | test_that("terminal", { 12 | tty <- ps_terminal(ps_handle()) 13 | if (is.na(tty)) skip("no terminal") 14 | expect_true(file.exists(tty)) 15 | 16 | ## It is a character special file 17 | out <- processx::run("ls", c("-l", tty))$stdout 18 | expect_equal(substr(out, 1, 1), "c") 19 | }) 20 | 21 | test_that("username, uids, gids", { 22 | if (Sys.which("ps") == "") skip("No ps program") 23 | ret <- system("ps -p 1 >/dev/null 2>/dev/null") 24 | if (ret != 0) skip("ps does not work properly") 25 | p1 <- processx::process$new("sleep", "10") 26 | on.exit(p1$kill(), add = TRUE) 27 | ps <- ps_handle(p1$get_pid()) 28 | expect_true(ps_is_running(ps)) 29 | 30 | ps2_username <- parse_ps(c("-o", "user", "-p", ps_pid(ps))) 31 | expect_equal(ps_username(ps), ps2_username) 32 | 33 | ps2_uid <- parse_ps(c("-o", "uid", "-p", ps_pid(ps))) 34 | expect_equal(ps_uids(ps)[["real"]], as.numeric(ps2_uid)) 35 | 36 | ps2_gid <- parse_ps(c("-o", "rgid", "-p", ps_pid(ps))) 37 | expect_equal(ps_gids(ps)[["real"]], as.numeric(ps2_gid)) 38 | }) 39 | 40 | 41 | test_that("send_signal", { 42 | p1 <- processx::process$new("sleep", "10") 43 | on.exit(p1$kill(), add = TRUE) 44 | ps <- ps_handle(p1$get_pid()) 45 | 46 | ps_send_signal(ps, signals()$SIGINT) 47 | timeout <- Sys.time() + 60 48 | while (Sys.time() < timeout && p1$is_alive()) Sys.sleep(0.05) 49 | expect_false(p1$is_alive()) 50 | expect_false(ps_is_running(ps)) 51 | expect_equal(p1$get_exit_status(), -signals()$SIGINT) 52 | }) 53 | 54 | test_that("terminate", { 55 | p1 <- processx::process$new("sleep", "10") 56 | on.exit(p1$kill(), add = TRUE) 57 | ps <- ps_handle(p1$get_pid()) 58 | 59 | ps_terminate(ps) 60 | timeout <- Sys.time() + 60 61 | while (Sys.time() < timeout && p1$is_alive()) Sys.sleep(0.05) 62 | expect_false(p1$is_alive()) 63 | expect_false(ps_is_running(ps)) 64 | expect_equal(p1$get_exit_status(), -signals()$SIGTERM) 65 | }) 66 | 67 | test_that("kill with grace", { 68 | p1 <- processx::process$new( 69 | px(), 70 | c("sigterm", "ignore", "outln", "setup", "sleep", "3"), 71 | stdout = "|" 72 | ) 73 | on.exit(p1$kill(), add = TRUE) 74 | ph1 <- p1$as_ps_handle() 75 | 76 | # need to wait until the SIGTERM handler is set up in px 77 | expect_equal(p1$poll_io(1000)[["output"]], "ready") 78 | expect_equal(ps_kill(ph1), "killed") 79 | }) 80 | 81 | test_that("kill with grace, multiple processes", { 82 | # ignored SIGTERM completely 83 | p1 <- processx::process$new( 84 | px(), 85 | c("sigterm", "ignore", "outln", "setup", "sleep", "3"), 86 | stdout = "|" 87 | ) 88 | on.exit(p1$kill(), add = TRUE) 89 | ph1 <- p1$as_ps_handle() 90 | 91 | # exits 0.5s later after SIGTERM 92 | p2 <- processx::process$new( 93 | px(), 94 | c("sigterm", "sleep", "0.5", "outln", "setup", "sleep", "3"), 95 | stdout = "|" 96 | ) 97 | on.exit(p2$kill(), add = TRUE) 98 | ph2 <- p2$as_ps_handle() 99 | 100 | # exits on SIGTERM 101 | p3 <- processx::process$new(px(), c("sleep", "3")) 102 | on.exit(p3$kill(), add = TRUE) 103 | ph3 <- p3$as_ps_handle() 104 | 105 | # wait until signal handlers are set up 106 | expect_equal(p1$poll_io(1000)[["output"]], "ready") 107 | expect_equal(p2$poll_io(1000)[["output"]], "ready") 108 | expect_equal( 109 | ps_kill(list(ph1, ph2, ph3), grace = 1000), 110 | c("killed", "terminated", "terminated") 111 | ) 112 | }) 113 | -------------------------------------------------------------------------------- /tests/testthat/test-ps.R: -------------------------------------------------------------------------------- 1 | test_that("issue #129", { 2 | if (!ps_os_type()[["POSIX"]]) return() 3 | pss <- ps(user = "root", after = as.POSIXct('2022-05-15', tz = "GMT")) 4 | expect_s3_class(pss, "tbl") 5 | }) 6 | 7 | test_that("can select columns", { 8 | skip_on_cran() 9 | expect_silent(ps(user = ps_username(), columns = c("pid", "username"))) 10 | expect_silent(ps(user = ps_username(), columns = "*")) 11 | }) 12 | -------------------------------------------------------------------------------- /tests/testthat/test-system.R: -------------------------------------------------------------------------------- 1 | test_that("ps_pids", { 2 | pp <- ps_pids() 3 | expect_true(is.integer(pp)) 4 | expect_true(Sys.getpid() %in% pp) 5 | }) 6 | 7 | test_that("ps", { 8 | pp <- ps() 9 | expect_true(inherits(pp, "tbl")) 10 | expect_true(Sys.getpid() %in% pp$pid) 11 | 12 | px <- processx::process$new(px(), c("sleep", "5")) 13 | x <- ps_handle(px$get_pid()) 14 | on.exit(px$kill(), add = TRUE) 15 | pp <- ps(after = Sys.time() - 60 * 60) 16 | ct <- lapply(pp$pid, function(p) { 17 | tryCatch(ps_create_time(ps_handle(p)), error = function(e) NULL) 18 | }) 19 | ct <- not_null(ct) 20 | expect_true(all(map_lgl(ct, function(x) x > Sys.time() - 60 * 60))) 21 | 22 | pp <- ps(user = ps_username(ps_handle())) 23 | expect_true(all(pp$username == ps_username(ps_handle()))) 24 | }) 25 | 26 | test_that("ps_boot_time", { 27 | bt <- ps_boot_time() 28 | expect_s3_class(bt, "POSIXct") 29 | expect_true(bt < Sys.time()) 30 | }) 31 | 32 | test_that("ps_os_type", { 33 | os <- ps_os_type() 34 | expect_true(is.logical(os)) 35 | expect_true(any(os)) 36 | expect_equal( 37 | names(os), 38 | c("POSIX", "WINDOWS", "LINUX", "MACOS") 39 | ) 40 | }) 41 | 42 | test_that("ps_is_supported", { 43 | expect_equal(any(ps_os_type()), ps_is_supported()) 44 | }) 45 | 46 | test_that("supported_str", { 47 | expect_equal(supported_str(), "Windows, Linux, Macos") 48 | }) 49 | 50 | test_that("ps_os_name", { 51 | expect_true(ps_os_name() %in% names(ps_os_type())) 52 | }) 53 | 54 | test_that("ps_users runs", { 55 | expect_error(ps_users(), NA) 56 | }) 57 | 58 | test_that("ps_cpu_count", { 59 | log <- ps_cpu_count(logical = TRUE) 60 | phy <- ps_cpu_count(logical = FALSE) 61 | if (!is.na(log) && !is.na(phy)) expect_true(log >= phy) 62 | if (!is.na(log)) expect_true(log > 0) 63 | if (!is.na(phy)) expect_true(phy > 0) 64 | }) 65 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("errno", { 2 | err <- errno() 3 | expect_true(is.data.frame(err)) 4 | 5 | expect_true("EINVAL" %in% err$name) 6 | expect_true("EBADF" %in% err$name) 7 | }) 8 | 9 | test_that("str_strip", { 10 | tcs <- list( 11 | list("", ""), 12 | list(" ", ""), 13 | list("a ", "a"), 14 | list(" a", "a"), 15 | list(" a ", "a"), 16 | list(" a ", "a"), 17 | list(character(), character()), 18 | list(c("", NA, "a "), c("", NA, "a")), 19 | list("\ta\n", "a") 20 | ) 21 | 22 | for (tc in tcs) { 23 | expect_identical(str_strip(tc[[1]]), tc[[2]]) 24 | } 25 | }) 26 | 27 | test_that("NA_time", { 28 | nat <- NA_time() 29 | expect_s3_class(nat, "POSIXct") 30 | expect_true(length(nat) == 1 && is.na(nat)) 31 | }) 32 | 33 | test_that("read_lines", { 34 | tmp <- tempfile() 35 | cat("foo\nbar\nfoobar", file = tmp) 36 | expect_silent(l <- read_lines(tmp)) 37 | expect_equal(l, c("foo", "bar", "foobar")) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-wait-inotify.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | expect_true(TRUE) 3 | }) 4 | 5 | if (ps_os_type()[["LINUX"]]) { 6 | fun <- function() { 7 | withr::local_envvar(PS_WAIT_FORCE_INOTIFY = "true") 8 | testthat::source_file(test_path("test-wait.R"), env = environment()) 9 | } 10 | fun() 11 | } 12 | -------------------------------------------------------------------------------- /tests/testthat/test-wait.R: -------------------------------------------------------------------------------- 1 | test_that("single process", { 2 | skip_on_cran() 3 | p <- processx::process$new(px(), c("sleep", "600")) 4 | on.exit(p$kill(), add = TRUE) 5 | ph <- ps_handle(p$get_pid()) 6 | 7 | expect_false(ps_wait(ph, 0)) 8 | expect_false(ps_wait(list(ph), 0)) 9 | 10 | tic <- Sys.time() 11 | expect_false(ps_wait(ph, 100)) 12 | toc <- Sys.time() 13 | expect_true(toc - tic >= as.difftime(0.1, units = "secs")) 14 | 15 | p$kill() 16 | tic <- Sys.time() 17 | expect_true(ps_wait(ph, 1000)) 18 | toc <- Sys.time() 19 | expect_true(toc - tic < as.difftime(1, units = "secs")) 20 | }) 21 | 22 | test_that("multiple processes", { 23 | skip_on_cran() 24 | p1 <- processx::process$new(px(), c("sleep", "600")) 25 | on.exit(p1$kill(), add = TRUE) 26 | ph1 <- ps_handle(p1$get_pid()) 27 | p2 <- processx::process$new(px(), c("sleep", "600")) 28 | on.exit(p2$kill(), add = TRUE) 29 | ph2 <- ps_handle(p2$get_pid()) 30 | p3 <- processx::process$new(px(), c("sleep", "600")) 31 | on.exit(p3$kill(), add = TRUE) 32 | ph3 <- ps_handle(p3$get_pid()) 33 | 34 | expect_equal(ps_wait(list(ph1, ph2, ph3), 0), c(FALSE, FALSE, FALSE)) 35 | expect_equal(ps_wait(list(ph1, ph2, ph3), 100), c(FALSE, FALSE, FALSE)) 36 | 37 | p1$kill() 38 | p2$kill() 39 | p3$kill() 40 | tic <- Sys.time() 41 | expect_equal(ps_wait(list(ph1, ph2, ph3), 1000), c(TRUE, TRUE, TRUE)) 42 | toc <- Sys.time() 43 | expect_true(toc - tic < as.difftime(1, units = "secs")) 44 | }) 45 | 46 | test_that("stress test", { 47 | skip_on_cran() 48 | pp <- lapply(1:100, function(i) { 49 | processx::process$new(px(), c("sleep", "2")) 50 | }) 51 | on.exit(lapply(pp, function(p) p$kill()), add = TRUE) 52 | pps <- lapply(pp, function(p) ps_handle(p$get_pid())) 53 | 54 | tic <- Sys.time() 55 | ret <- ps_wait(pps, 0) 56 | toc <- Sys.time() 57 | expect_equal(ret, rep(FALSE, length(pp))) 58 | expect_true(toc - tic < as.difftime(0.5, units = "secs")) 59 | 60 | tic <- Sys.time() 61 | ret <- ps_wait(pps, 3000) 62 | toc <- Sys.time() 63 | expect_equal(ret, rep(TRUE, length(pp))) 64 | expect_true(toc - tic < as.difftime(3, units = "secs")) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/testthat/test-windows.R: -------------------------------------------------------------------------------- 1 | if (!ps_os_type()[["WINDOWS"]]) return() 2 | 3 | test_that("uids, gids", { 4 | p1 <- processx::process$new(px(), c("sleep", "10")) 5 | on.exit(p1$kill(), add = TRUE) 6 | ps <- ps_handle(p1$get_pid()) 7 | expect_true(ps_is_running(ps)) 8 | 9 | err <- tryCatch(ps_uids(ps), error = function(e) e) 10 | expect_s3_class(err, "not_implemented") 11 | expect_s3_class(err, "ps_error") 12 | err <- tryCatch(ps_gids(ps), error = function(e) e) 13 | expect_s3_class(err, "not_implemented") 14 | expect_s3_class(err, "ps_error") 15 | }) 16 | 17 | test_that("terminal", { 18 | p1 <- processx::process$new(px(), c("sleep", "10")) 19 | on.exit(p1$kill(), add = TRUE) 20 | ps <- ps_handle(p1$get_pid()) 21 | expect_true(ps_is_running(ps)) 22 | 23 | expect_identical(ps_terminal(ps), NA_character_) 24 | }) 25 | 26 | ## TODO: username 27 | ## TODO: cpu_times 28 | ## TODO: memory_info 29 | 30 | test_that("total and available mem", { 31 | l <- .Call(ps__system_memory)[c("total", "avail")] 32 | expect_true(is.numeric(l$total)) 33 | expect_true(is.numeric(l$avail)) 34 | expect_lte(l$avail, l$total) 35 | }) 36 | -------------------------------------------------------------------------------- /tests/testthat/test-winver.R: -------------------------------------------------------------------------------- 1 | test_that("winver_ver", { 2 | cases <- list( 3 | list(c("", "Microsoft Windows [Version 6.3.9600]"), "6.3.9600"), 4 | list("Microsoft Windows [version 6.1.7601]", "6.1.7601"), 5 | list("Microsoft Windows [vers\u00e3o 10.0.18362.207]", "10.0.18362.207") 6 | ) 7 | 8 | source(system.file("tools", "winver.R", package = "ps"), local = TRUE) 9 | 10 | for (x in cases) expect_identical(winver_ver(x[[1]]), x[[2]]) 11 | }) 12 | 13 | test_that("winver_wmic", { 14 | cases <- list( 15 | list(c("\r", "\r", "Version=6.3.9600\r", "\r", "\r", "\r"), "6.3.9600"), 16 | list(c("\r", "\r", "version=6.3.9600\r", "\r", "\r", "\r"), "6.3.9600"), 17 | list(c("\r", "\r", "vers\u00e3o=6.3.9600\r", "\r", "\r", "\r"), "6.3.9600") 18 | ) 19 | 20 | source(system.file("tools", "winver.R", package = "ps"), local = TRUE) 21 | 22 | for (x in cases) expect_identical(winver_wmic(x[[1]]), x[[2]]) 23 | }) 24 | -------------------------------------------------------------------------------- /tools/linux-fs-types.txt: -------------------------------------------------------------------------------- 1 | name id 2 | adfs 44533 3 | affs 44543 4 | afs 1397113167 5 | anon_inode_fs 151263540 6 | autofs 391 7 | bdevfs 1650746742 8 | befs 1111905073 9 | bfs 464386766 10 | binfmtfs 1112100429 11 | bpf_fs 3405662737 12 | btrfs 2435016766 13 | btrfs_test 1936880249 14 | cgroup 2613483 15 | cgroup2 1667723888 16 | cifs_number 4283649346 17 | coda 1937076805 18 | coh 19920823 19 | cramfs 684539205 20 | debugfs 1684170528 21 | devfs 4979 22 | devpts 7377 23 | ecryptfs 61791 24 | efivarfs 3730735588 25 | efs 4278867 26 | ext 4989 27 | ext2_old 61265 28 | ext2 61267 29 | ext3 61267 30 | ext4 61267 31 | f2fs 4076150800 32 | fuse 1702057286 33 | futexfs 195894762 34 | hfs 16964 35 | hostfs 12648430 36 | hpfs 4187351113 37 | hugetlbfs 2508478710 38 | isofs 38496 39 | jffs2 29366 40 | jfs 827541066 41 | minix 4991 42 | minix2 5007 43 | minix2 9320 44 | minix22 9336 45 | minix3 19802 46 | mqueue 427819522 47 | msdos 19780 48 | mtd_inode_fs 288389204 49 | ncp 22092 50 | nfs 26985 51 | nilfs 13364 52 | nsfs 1853056627 53 | ntfs_sb 1397118030 54 | ocfs2 1952539503 55 | openprom 40865 56 | overlayfs 2035054128 57 | pipefs 1346981957 58 | proc 40864 59 | pstorefs 1634035564 60 | qnx4 47 61 | qnx6 1746473250 62 | ramfs 2240043254 63 | reiserfs 1382369651 64 | romfs 29301 65 | securityfs 1935894131 66 | selinux 4185718668 67 | smack 1128357203 68 | smb 20859 69 | smb2_number 4266872130 70 | sockfs 1397703499 71 | squashfs 1936814952 72 | sysfs 1650812274 73 | sysv2 19920822 74 | sysv4 19920821 75 | tmpfs 16914836 76 | tracefs 1953653091 77 | udf 352400198 78 | ufs 72020 79 | usbdevice 40866 80 | v9fs 16914839 81 | vxfs 2768370933 82 | xenfs 2881100148 83 | xenix 19920820 84 | xfs 1481003842 85 | _xiafs 19911021 86 | --------------------------------------------------------------------------------