.
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 | [](https://lifecycle.r-lib.org/articles/stages.html)
7 | [](https://github.com/r-lib/ps/actions/workflows/R-CMD-check.yaml)
8 | [](https://cran.r-project.org/package=ps)
9 | [](https://www.r-pkg.org/pkg/ps)
10 | [](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 |
--------------------------------------------------------------------------------