)]}'
{
  "log": [
    {
      "commit": "7dc983dba764f79366faf10a14980b40feb2f2d2",
      "tree": "8bcb0b58abe0c9db7ea60a6f8c9b70b44ecfda58",
      "parents": [
        "43f0465dfd8a5dc95bb55d2787586650a6e0dd41"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Aug 03 14:24:07 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Aug 03 14:24:07 2026"
      },
      "message": "[FreeBSD]: fix UnicodeDecodeError in cpu_freq()\n"
    },
    {
      "commit": "43f0465dfd8a5dc95bb55d2787586650a6e0dd41",
      "tree": "9f5b39bea76b4efa515451605a00ac172755fbad",
      "parents": [
        "b7fcd1777a212693ce809cd5a3bb7721e9e3546e"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sun Aug 02 09:37:33 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sun Aug 02 09:37:33 2026"
      },
      "message": "BSD: join 2 total phymem tests into 1\n"
    },
    {
      "commit": "b7fcd1777a212693ce809cd5a3bb7721e9e3546e",
      "tree": "1954c6f0e67ef992253e5e99a3de68ac8fcaef80",
      "parents": [
        "b5bfe84c6f0c725e34897e56b6e97e33ef8ba5b5"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sun Aug 02 00:26:53 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Aug 02 00:26:53 2026"
      },
      "message": "[SunOS] various fixes (#2953)\n\n`Process.gids` returned a `puids` namedtuple instead of `pgids`.\n`Process.nice` was offset by +20 compared to `getpriority(3)`.\n`Process.net_connections` returned UNIX sockets with `type\u003d-1` and\n`fd\u003d-1`. Also, `Process.net_connections` now raises :exc:`ZombieProcess`\ninstead of `RuntimeError` for zombie processes.\n\nCI still has 7 failures, but it would require adjusting / polluting\ntests, and for SunOS this is good enough."
    },
    {
      "commit": "b5bfe84c6f0c725e34897e56b6e97e33ef8ba5b5",
      "tree": "5b337f0707dfeab2fd161aa099f5ff58691819ab",
      "parents": [
        "ad04a6d90ca6b872278a6ac4375c948f90384f64"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 23:23:45 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 23:23:45 2026"
      },
      "message": "Re-enable old skipped tests now that we have fixed lots of stuff\n"
    },
    {
      "commit": "ad04a6d90ca6b872278a6ac4375c948f90384f64",
      "tree": "1662ab617fc12bf1e852546eae3bb3d6ff759fae",
      "parents": [
        "40d325b74fcd340658766ead9a10616df411a4c7"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 18:09:42 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 18:09:42 2026"
      },
      "message": "[OpenBSD] environ() raises OSError(EINVAL) for exiting processes (#2952)\n\nOn OpenBSD `kvm_getenvv()` fails with `EINVAL` for a process which\nstarted exiting (`PS_EXITING`, see\nhttps://github.com/openbsd/src/blob/master/sys/kern/kern_sysctl.c). This\nis the same race fixed for NetBSD in #2911, so reuse that logic:\nre-check the process and raise `ZombieProcess`. Also handle `EBUSY` in\nthe same way.\n\nDiscovered via a `test_all` flake on CI."
    },
    {
      "commit": "40d325b74fcd340658766ead9a10616df411a4c7",
      "tree": "58e968cd835499b530ac4755a0abfa4ca0c5c046",
      "parents": [
        "cf2f4dd7ce2c4f08859e841f669b511cbb9b16a0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 17:36:09 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 17:36:09 2026"
      },
      "message": "[OpenBSD] cpu_times() returned times averaged across CPUs instead of summed (#2951)\n\nOn OpenBSD `cpu_times()` read the `KERN_CPTIME` sysctl, which averages\ntimes across CPUs, see\nhttps://github.com/openbsd/src/blob/master/sys/kern/kern_sysctl.c. \n\nOn every other platform cpu_times() returns the sum, so on an N-CPU\nmachine OpenBSD values were N times smaller, and disagreed with\n`cpu_times(percpu\u003dTrue)`. Now we sum the per-CPU `KERN_CPTIME2`\ncounters, same as `per_cpu_times().`\n\nAlso re-enable `test_cpu_times_comparison` on OpenBSD, which was\ndisabled precisely because the API was broken."
    },
    {
      "commit": "cf2f4dd7ce2c4f08859e841f669b511cbb9b16a0",
      "tree": "260e59d4ea806b299bfd38e69f718b806780ab65",
      "parents": [
        "79d36846bd2184461c447ee34ecb64e55cc484ff"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 15:48:59 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 15:48:59 2026"
      },
      "message": "Restructure socks.c filtering  (#2950)\n\nUse a struct + common helper function to centralize the parsing of\nfilter args."
    },
    {
      "commit": "79d36846bd2184461c447ee34ecb64e55cc484ff",
      "tree": "af2c88918d6c70422fc16984d6ffaee3c710a430",
      "parents": [
        "2e737c8315182dec2880856fb0a9737bf2b1b8e5"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Sat Aug 01 14:28:39 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 14:28:39 2026"
      },
      "message": "Bump actions/cache from 4 to 6 in the github-actions group (#2944)"
    },
    {
      "commit": "2e737c8315182dec2880856fb0a9737bf2b1b8e5",
      "tree": "68eff7305a79dfd593398a7a8c7a2592ff7e416f",
      "parents": [
        "7a91b2907687381efdfa8e9be8cf6a58d3584aaf"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 14:28:09 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 14:28:09 2026"
      },
      "message": "[Windows] net_connections(): replace recursion with a loop, fix double decref (#2949)\n\nTwo defects in socks.c, both real in the code as written but with no\nreachable trigger in practice, hence no changelog entry.\n\n`__GetExtendedTcpTable()` and `__GetExtendedUdpTable()` called\nthemselves recursively to handle `ERROR_INSUFFICIENT_BUFFER`. In theory\nthis could recurse forever; in practice the buffer is allocated with 25%\nslack over what the sizing call asks for, and the sizing call itself has\nno documented failure mode with our parameters, so the recursion could\nnever go deeper than one retry. Still, a bounded `MAX_TRIES` loop is the\nright shape (same pattern as `GetAdaptersAddresses()` in net.c), and\nerror messages now include the Win32 error code. Since we retry on both\n`ERROR_INSUFFICIENT_BUFFER` and the undocumented transient\n`STATUS_UNSUCCESSFUL`, the retry / failure messages no longer claim\n\"buffer too small\" and report the last error code instead. See #2944.\n\nThe four `pylist_append_fmt()` call sites used the `\"N\"` format, which\nsteals the address tuple references even when the call fails, but the\nerror label decref\u0027d them again. Triggering it requires the append to\nfail, which basically means `MemoryError`. The references are now\ncleared right after the call, before checking the result."
    },
    {
      "commit": "7a91b2907687381efdfa8e9be8cf6a58d3584aaf",
      "tree": "c163a97424f0f9cb5ba17ea0dd4da3d6d9590e74",
      "parents": [
        "b2f9f8c71793dc38c08e9d007426e959ab949019"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 14:01:43 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 14:01:43 2026"
      },
      "message": "psutil_debug() / psutil_warn() fixes\n\nFollow up of #2948, addressing 2 issues:\n- psutil_debug() args are again not evaluated when debug mode is off\n  (the old macro behavior, lost in the refactoring)\n- _psutil_warn_impl() no longer uses the str_*() helpers, whose\n  failure path calls psutil_warn() itself: with a long enough\n  __FILE__ the recursion never bottomed out\n"
    },
    {
      "commit": "b2f9f8c71793dc38c08e9d007426e959ab949019",
      "tree": "0b3136da8a603ba0e91e1d6b84fc0477496a7a8c",
      "parents": [
        "b5132425907729d70c2797eb5971706bf3942186"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 13:45:53 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 13:45:53 2026"
      },
      "message": "Add missing copyright header\n"
    },
    {
      "commit": "b5132425907729d70c2797eb5971706bf3942186",
      "tree": "507d724252803ee9e75447d0e4263f9ad6e9197d",
      "parents": [
        "45afc819b57a4bc807a81ac90070c62298c69117"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 13:31:51 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 13:31:51 2026"
      },
      "message": "Try to fix flaky Popen test on NetBSD\n"
    },
    {
      "commit": "45afc819b57a4bc807a81ac90070c62298c69117",
      "tree": "2fecc4daa364e19ceb71c2cd5801c605df378f50",
      "parents": [
        "ded49a3a720c8501bcf0d32ca4a31e09007cfd19"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 13:28:06 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 13:28:06 2026"
      },
      "message": "Introduce C-level critical warning messages (#2948)\n\nThere are circumstances in C where something is clearly \"off\" but not \"off\"\nenough to justify raising an exception, e.g. when we return incomplete results\nafter a sanity check on kernel data failed. In these cases we signal the event\nvia `psutil_debug()`, which prints a message to stderr, but only if psutil is\nin debug mode (`PSUTIL_DEBUG\u003d1` env var), which is almost never enabled. So in\npractice these events go unnoticed.\n\nWe add a new `psutil_warn()` C helper that emits an actual `RuntimeWarning`, so\nit reaches the Python layer, and use it in the (rare) places where it\u0027s\njustified. The warning message includes the C file + line number where it\noriginated from.\n\nSome practical notes on how warnings behave:\n\n- With Python\u0027s default filters the same warning is printed only once per\n  process, per calling location. Repeated calls from the same place stay silent\n  after the first one.\n- It can be silenced with the standard machinery:\n  `warnings.filterwarnings(\"ignore\", category\u003dRuntimeWarning)`, `python -W\n  ignore::RuntimeWarning`, or the `PYTHONWARNINGS` env var.\n- With `-W error` (warnings turned into exceptions, common in test suites) the\n  exception is discarded: psutil functions never fail because of these\n  warnings.\n\nFixes #@2947."
    },
    {
      "commit": "ded49a3a720c8501bcf0d32ca4a31e09007cfd19",
      "tree": "2999fb586c10b51f77c44d9a46de24267756dd2f",
      "parents": [
        "435ab975920bc87230c46f1562f31de10d63667d"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 11:53:46 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 11:53:46 2026"
      },
      "message": "[macOS] net_io_counters(): bounds check fired on every call, require only the route msg header\n"
    },
    {
      "commit": "435ab975920bc87230c46f1562f31de10d63667d",
      "tree": "3d3c3c9bf0866535ccfbb48cd7e0fc33d8af1142",
      "parents": [
        "d87e34d12b3dc2bfbb1a9ed83c57b5b112662516"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 11:28:55 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 11:28:55 2026"
      },
      "message": "str.c: make truncation behave the same on all platforms\n\n str_copy() and str_append() were implemented with a different libc\n function per platform, and each behaved differently when the source\n string didn\u0027t fit:\n\n - Windows (strcpy_s / strcat_s): a too small destination invokes the\n   CRT invalid parameter handler, which by default kills the process.\n   The error checks after those calls were unreachable in that case.\n - Linux / SunOS / AIX (strncpy / strncat): silent truncation,\n   returning 0. The docstring promised -1 on truncation.\n - macOS / BSD (strlcat): the only branch doing what the docstring\n   said. It didn\u0027t guard against an unterminated destination though,\n   which strlcat can read past.\n\n Replace the three branches with a single strlen() + memcpy()\n implementation. On truncation every platform now keeps as much of the\n source as fits, null-terminates, and returns -1.\n\n Also rename _error() to str_error() (identifiers starting with an\n underscore are reserved at file scope) and make it variadic. Route\n str_format() failures through it: before, a truncated str_format()\n only printed a debug message, so PSUTIL_TESTING mode did not fail\n loudly like it does for the other str_*() functions.\n\n Co-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "d87e34d12b3dc2bfbb1a9ed83c57b5b112662516",
      "tree": "13af751a0573021bd29efd3ea12699255ab53912",
      "parents": [
        "90da475413814ecbc54602ecf48f0d30124bd1fe"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:55:14 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:55:14 2026"
      },
      "message": "check_pid_range(): the negative pid check was dead code on Windows\n"
    },
    {
      "commit": "90da475413814ecbc54602ecf48f0d30124bd1fe",
      "tree": "893cbdd38081439c8609210d351532c591c9129e",
      "parents": [
        "59dcd98df9b401aa26b7898d5bcc1d3f303f2bbf"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:49:52 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:49:52 2026"
      },
      "message": "[Windows] heap_trim(): don\u0027t mistake stale last-error for HeapCompact() failure\n"
    },
    {
      "commit": "59dcd98df9b401aa26b7898d5bcc1d3f303f2bbf",
      "tree": "0461f3f5ccc537b54f5032a0efc324c583af270f",
      "parents": [
        "60a3f7861b6e86579f7df338bcd5d9b97a8ea99f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:43:12 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 10:43:12 2026"
      },
      "message": "[Windows] heap_info() can return wrong values if the number of heaps changes while it runs (#2946)\n\n`psutil.heap_info()` on Windows calls `GetProcessHeaps()` twice: once to\nget the number of heaps, once to fill the handles buffer. If another\nthread creates or destroys a heap in between (any DLL in the process can\ndo that), the two counts disagree. If a heap was destroyed, the code\niterates over more handles than were actually stored in the buffer,\ncomparing memory regions against uninitialized memory, which can\nsilently corrupt the returned `mmap_used`. If a heap was created, the\nreturned `heap_count` is stale."
    },
    {
      "commit": "60a3f7861b6e86579f7df338bcd5d9b97a8ea99f",
      "tree": "5c80def2bb6db37d2e27e67cd221a6ec4514f61f",
      "parents": [
        "226f9f20c685b2f37a01c1ef33a30b4f138ec6a4"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:17:28 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:17:28 2026"
      },
      "message": "[Windows] users(): debug trace empty-list returns, guard WTSFreeMemory(NULL), use AF_INET\n"
    },
    {
      "commit": "226f9f20c685b2f37a01c1ef33a30b4f138ec6a4",
      "tree": "389729ea0142efbcf11ef3f42bc4bf47ef993f3a",
      "parents": [
        "47f039c66bc7206120828840fd6d5dd97aabc748"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 10:01:59 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 10:01:59 2026"
      },
      "message": "Release the GIL around more critical paths (#2945), see #2939\n\nA continuation of #2939."
    },
    {
      "commit": "47f039c66bc7206120828840fd6d5dd97aabc748",
      "tree": "89b6b4245d68e3ab53efe109d94b71d1bf35a35f",
      "parents": [
        "0a6202f4f5bab029a696f7d1d58dffd6eeb0e3ae"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 09:05:58 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 09:05:58 2026"
      },
      "message": "[Windows] net_if_stats(): fix py_is_up ref leak, minor cleanups\n"
    },
    {
      "commit": "0a6202f4f5bab029a696f7d1d58dffd6eeb0e3ae",
      "tree": "b931243ca333a4feb264a5a32d027b5b393f2848",
      "parents": [
        "f3be95d77caedc02b494fc6bbae6c29f7289fbe5"
      ],
      "author": {
        "name": "Omprakash Chauhan",
        "email": "91268538+omprakash2929@users.noreply.github.com",
        "time": "Sat Aug 01 09:04:27 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 09:04:27 2026"
      },
      "message": "[Windows] fix net_if_stats() speed overflow for interfaces \u003e4.29 Gbps (#2924)\n\n`net_if_stats()` was returning `4294967295` (32-bit overflow) as the\nspeed for network interfaces with link speed greater than 4.29 Gbps\n(e.g. 5 Gbps).\n\n### Root cause\nThe function used the legacy `GetIfTable()` API and `MIB_IFROW`\nstruct, where `dwSpeed` is a 32-bit `DWORD`. This overflows for any\ninterface speed above ~4.29 Gbps.\n\n### Fix\nMigrated `psutil_net_if_stats()` to use `GetIfEntry2()` with the\n`MIB_IF_ROW2` struct instead - same approach already used by\n`net_io_counters()` in this file. `TransmitLinkSpeed` in `MIB_IF_ROW2`\nis a 64-bit `ULONG64`, so it correctly represents higher speeds.\n\n### Testing\n- Built locally on Windows with `pip install -e \".[test]\"`\n- Verified output manually via `psutil.net_if_stats()` - speeds now\n  show correct values instead of overflowing\n- Ran existing test suite: `test_net_if_stats` passes\n\nFixes #2655"
    },
    {
      "commit": "f3be95d77caedc02b494fc6bbae6c29f7289fbe5",
      "tree": "8351f468b07812c4ebfe9659e6c252a2050e576d",
      "parents": [
        "bb57c072c8a7f5827703440354f7622217386b1f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 01:30:37 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 01:30:37 2026"
      },
      "message": "Fix #2848, BSD: buffer overflow in net_io_counters()\n\nsdl_nlen comes from the kernel routing data and\nwas used unchecked both as a copy length and as a\nwrite index into a 32 byte stack buffer. Clamp it,\nthe way osx/net.c already does. Also use memcpy()\nrather than strncpy(), since sdl_data is not NUL\nterminated.\n"
    },
    {
      "commit": "bb57c072c8a7f5827703440354f7622217386b1f",
      "tree": "66d7c2debae072c1b9efd8019eff20015bb1d25c",
      "parents": [
        "dd8d692211ee67900c45d1e5ad759be4c28471c0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 01:03:12 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 01:03:12 2026"
      },
      "message": "[Windows] enable clang-format for ntextapi.h\n"
    },
    {
      "commit": "dd8d692211ee67900c45d1e5ad759be4c28471c0",
      "tree": "b4c1f9399aa9c5d5bfdaa926d71229586ad6ee7c",
      "parents": [
        "dcaa7ad4006dc60ea3fb6e2317eb51e6101a9951"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:56:03 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:56:03 2026"
      },
      "message": "[Windows] services.c: drop a misplaced ERROR_MUI_FILE_NOT_FOUND check\n"
    },
    {
      "commit": "dcaa7ad4006dc60ea3fb6e2317eb51e6101a9951",
      "tree": "2d0d6fe2ae1a0945f82c6acc12138c0eb1382524",
      "parents": [
        "f52522258cc38980994b2eccc624b47e8ae9b763"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:42:09 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:42:09 2026"
      },
      "message": "[Windows] win_service_iter(): don\u0027t walk the results if enumeration failed (#2943)\n\nEnumServicesStatusExW() was called in a loop until it stopped returning\nERROR_MORE_DATA, but its result was never checked afterwards, so a failure\nlooked exactly like success. We then walked lpService[i] with lpService\nstill NULL and srvCount uninitialized. Also check malloc(), fix a\nPy_DECREF() on a NULL py_name, and release py_retlist when OpenSCManager()\nfails.\n"
    },
    {
      "commit": "f52522258cc38980994b2eccc624b47e8ae9b763",
      "tree": "00a0be87b04fd1827c9b72c83b425c1b9c90d2db",
      "parents": [
        "d74884881cfa91bb9cb474c5081a047f3ca0b287"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:25:55 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:25:55 2026"
      },
      "message": "[Windows] WindowsService.description(): don\u0027t fail with ERROR_FILE_NOT_FOUND (#2383)\n"
    },
    {
      "commit": "d74884881cfa91bb9cb474c5081a047f3ca0b287",
      "tree": "b40db2fa2e1a47160d18269f3c35dfbf8d6c9711",
      "parents": [
        "277829b06c5ee95b8b9d8db9762eb0eac273db46"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:15:57 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Sat Aug 01 00:15:57 2026"
      },
      "message": "[Windows] cleanup security.c\n\nTpPrevious was uninitialized and we OR into Privileges[0].Attributes,\nwhich\nAdjustTokenPrivileges() leaves untouched when the token doesn\u0027t hold the\nprivilege. Uninitialized read on the common path, harmless in practice\nbut UB.\n"
    },
    {
      "commit": "277829b06c5ee95b8b9d8db9762eb0eac273db46",
      "tree": "2ee92944e27c0fde665f4429a7108eeccaac7934",
      "parents": [
        "783978c1f94c2fca4c5dd2031781561e23d1426f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 23:42:50 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 23:42:50 2026"
      },
      "message": "[Windows] net.c: fix stale comments after #2863\n"
    },
    {
      "commit": "783978c1f94c2fca4c5dd2031781561e23d1426f",
      "tree": "d42082c1c064d207d7800b0439f94461254a6bfb",
      "parents": [
        "35529fae02722c8fa586a091992946e64fab1094"
      ],
      "author": {
        "name": "arman",
        "email": "129011616+Arman-Luthra@users.noreply.github.com",
        "time": "Fri Jul 31 23:37:07 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 23:37:07 2026"
      },
      "message": "Windows: make the net_*() APIs 2x - 5x faster (#2863)\n\nAll three net APIs go through `GetAdaptersAddresses()`, which MSDN\ndescribes as expensive (\"requires a significant amount of network\nresources and time to complete since all of the low-level network\ninterface tables must be traversed\"). We called it twice per invocation\nand asked it for data we never read.\n\n- Call it once: start with the 15KB buffer MSDN recommends and retry on\n  ERROR_BUFFER_OVERFLOW, instead of one call to determine the size plus\n  a second one to fill the buffer. MSDN explicitly discourages the\n  latter.\n- `net_io_counters()` and `net_if_stats()` also skip unicast addresses,\n  the most expensive part to collect and one neither of them reads. They\n  only need IfIndex, FriendlyName and Description.\n\nOn a machine with 8 NICs, against 7.2.2: `net_io_counters()` 4.96 -\u003e\n0.88 ms, `net_if_stats()` 6.79 -\u003e 2.67 ms, `net_if_addrs()` 5.20 -\u003e 2.41\nms. Cost is proportional to the number of NICs.\n\nCo-authored-by: Giampaolo Rodola \u003cg.rodola@gmail.com\u003e"
    },
    {
      "commit": "35529fae02722c8fa586a091992946e64fab1094",
      "tree": "f0f7d3d696ce61549013b5519a4d32fb8268dc58",
      "parents": [
        "1d57f4a45ecdc99a65747dcaeff4de29f614dbc0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 23:24:47 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 23:24:47 2026"
      },
      "message": "[Windows] restructure ntextapi.h (#2942)\n\nRestructure `ntextapi.h`. No longer include `\u003cwinternl.h\u003e`, which\nprovides only a subset of the private APIs we need, and only forces us\nto circumvent existing definitions defined in there with odd namings.\n\nThis is how SystemInformer does this, so we follow its lead:\n\nhttps://github.com/winsiderss/systeminformer/blob/245c808f0/phnt/include/ntexapi.h"
    },
    {
      "commit": "1d57f4a45ecdc99a65747dcaeff4de29f614dbc0",
      "tree": "caa990947a6fdb9ff3d68ee2b9a2b828b25a46d2",
      "parents": [
        "5010f4e7fbd5c8195cf6f813979b9142708181d1"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:43:00 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:43:00 2026"
      },
      "message": "[Windows] net_if_addrs(): size buffers to what they actually hold\n"
    },
    {
      "commit": "5010f4e7fbd5c8195cf6f813979b9142708181d1",
      "tree": "b1054f7d28c7d8c40710c936db534313130b54d7",
      "parents": [
        "4dd1310b552915586e8b22575a2a6f4a586f710e"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:41:41 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:41:41 2026"
      },
      "message": "[Windows] retry GetAdaptersAddresses() and skip the data we don\u0027t use\n"
    },
    {
      "commit": "4dd1310b552915586e8b22575a2a6f4a586f710e",
      "tree": "dd809b410891ec07ce92173fbdfc94444076195c",
      "parents": [
        "05cf4d209acc9c08cb82215e7235c802d794eba0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:11:46 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:11:46 2026"
      },
      "message": "[Windows] net.c: include the Win32 error code in RuntimeError messages\n"
    },
    {
      "commit": "05cf4d209acc9c08cb82215e7235c802d794eba0",
      "tree": "9016382b400505e03226304279d778a8effb2793",
      "parents": [
        "3e7d7581443ca8788088aa8bcc092fb9c867a760"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:08:44 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:08:44 2026"
      },
      "message": "[Windows] net_io_counters(): skip NICs which disappear mid-call (#2941)\n"
    },
    {
      "commit": "3e7d7581443ca8788088aa8bcc092fb9c867a760",
      "tree": "35f3075c0341194e73b9a1a06cd618c3785a4129",
      "parents": [
        "a4f852ee82c336b29df247e74118fb5b2b2a8746"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:06:03 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:06:03 2026"
      },
      "message": "[Windows] net_if_addrs(): fix error paths not setting or propagating the exception\n"
    },
    {
      "commit": "a4f852ee82c336b29df247e74118fb5b2b2a8746",
      "tree": "32d4602bcb6b77fc0b3fdd50539785545e448d7b",
      "parents": [
        "3037727fad29a6467a5cda54d2196f3292ba964b"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:02:39 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 21:02:39 2026"
      },
      "message": "[Windows] net_if_addrs(): don\u0027t report an IPv4 netmask for IPv6 addresses (#2940)\n"
    },
    {
      "commit": "3037727fad29a6467a5cda54d2196f3292ba964b",
      "tree": "a707f2f98ac7ef6151a9b29621b577e58b157151",
      "parents": [
        "7ff788b8659b1362f07e877626aec4d19795e000",
        "c8648d6e729af1f92547f2520a6da795c50591a3"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 20:48:27 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 20:48:27 2026"
      },
      "message": "Merge from master\n"
    },
    {
      "commit": "c8648d6e729af1f92547f2520a6da795c50591a3",
      "tree": "a707f2f98ac7ef6151a9b29621b577e58b157151",
      "parents": [
        "f6dbd2ecc05f3b14c56e5551d4f5edbafc7f5fc0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 20:47:15 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 20:47:15 2026"
      },
      "message": "Release the GIL around blocking syscalls (#2939)\n\nThis is a full sweep of all .c files, looking for syscalls which can\npotentially block, and therefore hold the GIL. That means that in a\nmulti threaded Python app, calling a slow psutil function results in\nblocking ALL Python threads, and therefore completely freeze the app for\na while. This is the problem that `Py_BEGIN_ALLOW_THREADS` /\n`Py_END_ALLOW_THREADS` solve.\n\nWorth mentioning:\n\n- macOS `memory_full_info()`: the VM region walk can hang forever on a\nprocess you don\u0027t own (see #2885). The hang is still there, but it no\nlonger freezes the other threads.\n- Windows `open_files()`: waits up to 100ms per handle for its worker\n(1s more if it has to kill it), e.g. for a file on an unreachable SMB\nshare.\n- Windows `win_service_iter()` / `net_connections()`: hundreds of RPCs\ninto services.exe. Incidentally, these 2 APIs are the slowest tests we\nhave on Windows CI, so the problem was real.\n- Windows `username()`: `LookupAccountSidW()` can hang while querying\nthe domain controller.\n- `net_*` functions using `ioctls` (SIOCGIF*, SIOCETHTOOL): all NIC\ndrivers can take a while to answer."
    },
    {
      "commit": "7ff788b8659b1362f07e877626aec4d19795e000",
      "tree": "9c758dbb85be691627cb6b8cf8abd8fe6693bc9a",
      "parents": [
        "f6dbd2ecc05f3b14c56e5551d4f5edbafc7f5fc0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:07:42 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:07:42 2026"
      },
      "message": "Windows: make Pdh* calls show status code in case of err\n"
    },
    {
      "commit": "f6dbd2ecc05f3b14c56e5551d4f5edbafc7f5fc0",
      "tree": "6be35cc6e4322303d711e8b8676e5a590e976350",
      "parents": [
        "feb81885e23ccab2d9f315046334b78497087d9e"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:03:09 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:03:09 2026"
      },
      "message": "Fix #2938: disk_partitions() mount points get the same opts as their parent drive\n"
    },
    {
      "commit": "feb81885e23ccab2d9f315046334b78497087d9e",
      "tree": "62a06ca279324461c8ffd7578650e3855635100d",
      "parents": [
        "764aec57294fdcc040380aebc46d351a93132353"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:01:33 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:01:33 2026"
      },
      "message": "disk_partitions(): drop no-op str_append() of an empty string\n"
    },
    {
      "commit": "764aec57294fdcc040380aebc46d351a93132353",
      "tree": "2052c3f8252617a4a58e09c07bb1708c821e7d73",
      "parents": [
        "9d580c1400031483b2009e88435c60fcf1939172"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:00:29 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 19:00:29 2026"
      },
      "message": "disk_partitions(): pass 0 as the volume name size, we don\u0027t request it\n"
    },
    {
      "commit": "9d580c1400031483b2009e88435c60fcf1939172",
      "tree": "af86c5a3c7891c11df07740a67c59212ae0b29ae",
      "parents": [
        "f5aac9b8dc45366da323fa50dceab3ac92fdf265"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:59:44 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:59:44 2026"
      },
      "message": "disk_partitions(): fs_type is a string, not an array of pointers\n"
    },
    {
      "commit": "f5aac9b8dc45366da323fa50dceab3ac92fdf265",
      "tree": "74b668bd887123eaac65adb8b41ca12325cac659",
      "parents": [
        "0a50b0b691615d953ad670fe5f7f39913286eb60"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:58:18 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:58:18 2026"
      },
      "message": "Fix failing test in case process disappears\n"
    },
    {
      "commit": "0a50b0b691615d953ad670fe5f7f39913286eb60",
      "tree": "18ad314614c4bce1db662ff72f91b679f1cdc549",
      "parents": [
        "9f6fa8ed9ada7bc28a30414fa47f055bee62ba49"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:54:22 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:54:22 2026"
      },
      "message": "Fix #2937: disk_io_counters() grow the ioctl buffer for real instead of lying about its size\n"
    },
    {
      "commit": "9f6fa8ed9ada7bc28a30414fa47f055bee62ba49",
      "tree": "72beb61c58ab96acb9015faad35634698728522e",
      "parents": [
        "d059e84109579a9fca6503b46a7d7ec8a194edc4"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:51:13 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:51:13 2026"
      },
      "message": "Parse bool args with the \"p\" format instead of PyObject_IsTrue()\n"
    },
    {
      "commit": "d059e84109579a9fca6503b46a7d7ec8a194edc4",
      "tree": "59c36c61de096298386a7c7fd940eedb5f99db75",
      "parents": [
        "fc2bb96fe9d4f508c78de886732d8af23c586505"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:36:37 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:36:37 2026"
      },
      "message": "memory_maps(): return mapped paths longer than 260 chars in full\n"
    },
    {
      "commit": "fc2bb96fe9d4f508c78de886732d8af23c586505",
      "tree": "b97340be9f60ee1982e876655432eaf4532fc82e",
      "parents": [
        "c54b41d98abe6a6236c43e6e4aa572014b53e61a"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:35:09 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:35:09 2026"
      },
      "message": "Remove dead psutil_sysctlbyname_malloc(); its only caller went away in f5251992 (#2782)\n"
    },
    {
      "commit": "c54b41d98abe6a6236c43e6e4aa572014b53e61a",
      "tree": "187500eedf9039275e689017ce8f117cc7dce37f",
      "parents": [
        "0494f84c1990fd3087ae1f02ac7c04f29abf11f9"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:29:07 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:29:07 2026"
      },
      "message": "Remove dead declarations in .h files\n"
    },
    {
      "commit": "0494f84c1990fd3087ae1f02ac7c04f29abf11f9",
      "tree": "83a5122876e665b956690785d423adc00f9f27f9",
      "parents": [
        "ad610988e2f521cacfdcad040480e8693bba4caf"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:25:47 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:25:47 2026"
      },
      "message": "check_winver(): return -1 on error like the other init functions\n"
    },
    {
      "commit": "ad610988e2f521cacfdcad040480e8693bba4caf",
      "tree": "a017486e0961a7e91800c1b958ba411c4f892306",
      "parents": [
        "f79d95c386662868469d14a58e8cfc305a3f0170"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:24:36 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:24:36 2026"
      },
      "message": "loadlibs(): resolve ntdll symbols via GetModuleHandle, uniformly\n"
    },
    {
      "commit": "f79d95c386662868469d14a58e8cfc305a3f0170",
      "tree": "5789742cda564c8d25429dd650aca5c6ee24414f",
      "parents": [
        "615f6c233f57f6b2ee7009f8115a5de9615c401d"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:23:18 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:23:18 2026"
      },
      "message": "cpu_freq(): raise OSError from the NTSTATUS instead of a generic RuntimeError\n"
    },
    {
      "commit": "615f6c233f57f6b2ee7009f8115a5de9615c401d",
      "tree": "0b51e251ad470f43bdfb2fbbaf50ac0d3c32a78f",
      "parents": [
        "dfca6b0cc3a39c468b2db3ad9643a4f681f52d3e"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:22:34 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:22:34 2026"
      },
      "message": "cpu_stats(): don\u0027t mix _SYSTEM_INTERRUPT_INFORMATION with winternl.h\u0027s SYSTEM_INTERRUPT_INFORMATION\n"
    },
    {
      "commit": "dfca6b0cc3a39c468b2db3ad9643a4f681f52d3e",
      "tree": "7f11437278ab827c24ad5c2a4b47aae0b3cbea0f",
      "parents": [
        "3ea90fd9940d3bb426226c006da4b215b5c1a979"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:21:43 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:21:43 2026"
      },
      "message": "cpu_stats(): allocate one SYSTEM_PERFORMANCE_INFORMATION, not ncpus\n"
    },
    {
      "commit": "3ea90fd9940d3bb426226c006da4b215b5c1a979",
      "tree": "7d7b28e04d72f108b7311d23512144bc469cdecc",
      "parents": [
        "068b4bbdf1e435a077526f24b665a2c0e02eeeb4"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:20:08 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:20:08 2026"
      },
      "message": "Fix #2965: per-CPU times/stats read uninitialized memory on \u003e 64 CPU systems\n"
    },
    {
      "commit": "068b4bbdf1e435a077526f24b665a2c0e02eeeb4",
      "tree": "8bcbfc6d9825e93f4ed3d3acf85a2571e918bb02",
      "parents": [
        "3bf3d13619823abf7361c64d2731af8dbd39116b"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:16:29 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 18:16:29 2026"
      },
      "message": "Fix #2847: cpu_stats() dereferenced spi buffer after free()\n"
    },
    {
      "commit": "3bf3d13619823abf7361c64d2731af8dbd39116b",
      "tree": "f5334c4722fe4566f6f1d3cf9edaeeb8eb14408b",
      "parents": [
        "dff6ebf9b43cd640141ef93a7be5195aa063e6fa"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:40:47 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:40:47 2026"
      },
      "message": "Windows: drop support for PyPy \u003c 7.3.14; fixes #2963\n"
    },
    {
      "commit": "dff6ebf9b43cd640141ef93a7be5195aa063e6fa",
      "tree": "41e165f4e0d20cbbcde363e1ecd1087f16d6736b",
      "parents": [
        "b2af2f9776c7eb08100d31d905db2af04ec2b5a6"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:16:04 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:16:04 2026"
      },
      "message": "check_winver(): don\u0027t memset() dwOSVersionInfoSize after setting it; check RtlGetVersion() status\n"
    },
    {
      "commit": "b2af2f9776c7eb08100d31d905db2af04ec2b5a6",
      "tree": "2b7e6598c4e1c978f354333e7e2aceb41a868016",
      "parents": [
        "e132dd1bfbacf4cae4063e91aabff77daa8cd7f7"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:13:07 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:13:07 2026"
      },
      "message": "Window: define psutil_raise_for_nt_status() helper\n"
    },
    {
      "commit": "e132dd1bfbacf4cae4063e91aabff77daa8cd7f7",
      "tree": "84ec0ff1f24db08398f214b09a52a8aef83cfce8",
      "parents": [
        "e248c38fbde4dc6e836850a95a3c6ca018f49bcc"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:09:18 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:09:18 2026"
      },
      "message": "proc_wait(): handle OpenProcess() failing with ERROR_SUCCESS (#1877)\n"
    },
    {
      "commit": "e248c38fbde4dc6e836850a95a3c6ca018f49bcc",
      "tree": "2bab5734aab888aa312e2b892750737f2cff4974",
      "parents": [
        "08820c582a390e5b0d75a890fbf908836acc0a1a"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:06:54 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:06:54 2026"
      },
      "message": "proc_exe(): don\u0027t let bufferSize overflow the USHORT MaximumLength\n"
    },
    {
      "commit": "08820c582a390e5b0d75a890fbf908836acc0a1a",
      "tree": "445366020ef9e313b04e02a89ac4091804c2d832",
      "parents": [
        "a3dd353c4a6ccc7d4c682772ae2abed60c2d347a"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:05:39 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:05:39 2026"
      },
      "message": "proc_username(): fix potential double free in the buffer-resize retry path\n"
    },
    {
      "commit": "a3dd353c4a6ccc7d4c682772ae2abed60c2d347a",
      "tree": "c70e426bc539b1e99082872298b04b4e4a3650f7",
      "parents": [
        "56467f64861822516c473892ba8f53679c9e7b25"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:04:19 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:04:19 2026"
      },
      "message": "Fix #2935: proc_kill() leaked a handle when TerminateProcess() failed\n"
    },
    {
      "commit": "56467f64861822516c473892ba8f53679c9e7b25",
      "tree": "a249ba40ecdb264927866981d0c4118a6f787200",
      "parents": [
        "8602855e3f73dc388029e227ffc8f07347356792"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:02:21 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 17:02:21 2026"
      },
      "message": "Fix #2934: memory_maps() may crash with stack buffer overflow (GetMappedFileNameW size is in chars, not bytes)\n"
    },
    {
      "commit": "8602855e3f73dc388029e227ffc8f07347356792",
      "tree": "1a3d28de7a9af881c59b05e932d90a9eb9671647",
      "parents": [
        "563fb6283dde4e9fcaa85a13970be582cc740a9d"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 16:59:14 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 16:59:14 2026"
      },
      "message": "Use FREE / MALLOC macros instead of HeapAlloc / HeapFree\n"
    },
    {
      "commit": "563fb6283dde4e9fcaa85a13970be582cc740a9d",
      "tree": "67a0d96afa232bb99a49939d448b1c47c7382ac3",
      "parents": [
        "2b78a340c37bcebbf55e686c1e3a6c80dd5e7332"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 12:27:18 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 12:27:18 2026"
      },
      "message": "Split psutil_check_phandle() into phandle_is_running() + OpenProcess error handling in psutil_handle_from_pid()\n"
    },
    {
      "commit": "2b78a340c37bcebbf55e686c1e3a6c80dd5e7332",
      "tree": "6751d9894135ea3e7fad0269fb3b79d91557aee5",
      "parents": [
        "078f2f08d2ccea916a42f9571ab8bd40d958e7a1"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 12:10:09 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 12:10:09 2026"
      },
      "message": "[Windows] Refactor proc_info.c + rename it to proc_peb.c (#2933)\n\nIt contained things that really belonged to `proc_utils.c`. I renamed it\nfrom `proc_info.c` to `proc_peb.c`, which now hosts only 3 \"public\"\nprocess functions: cmdline(), cwd() and environment()."
    },
    {
      "commit": "078f2f08d2ccea916a42f9571ab8bd40d958e7a1",
      "tree": "f433fe3cba27c5b9e991a24a02ec6f427a06a85c",
      "parents": [
        "335a5f0f5a4e8280f9640a75fd6fc0d3570306e0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Fri Jul 31 07:53:59 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 07:53:59 2026"
      },
      "message": "Windows: make `Process.open_files()` 140x - 400x faster (#2932)\n\n`Process.open_files()` enumerated every handle in the system on every\ncall,\ndiscarded the ones not belonging to the target process, then spawned one\nthread\nper surviving handle to query its name, abandoning it on timeout.\n\nThis PR:\n\n- enumerates handles per process with\n  `NtQueryInformationProcess(ProcessHandleInformation)`.\n- skips the handles which are not files by object type index, before\n  duplicating them.\n- uses one worker thread per call instead of one per handle, killing it\nwith\n`TerminateThread()` on timeout. That is safe now that its body is\nstrictly\n  syscalls, holding no user-mode lock (see #1967).\n- filters out directories in C, on the handle, instead of calling\n`os.stat()`\n  on each path in Python.\n\nA handle on an unreachable network share no longer stalls the call for\nthe SMB\nsession timeout (around 1 minute), since the `os.stat()` it used to do\nhad no\ntimeout around it; it now costs one 100 ms worker timeout.\n\nThe two \"too slow on Windows\" skips in `test_process_all.py` and\n`test_memleaks.py` are removed.\n\n## Benchmark\n\n```python\nimport time\nimport psutil\n\np \u003d psutil.Process()\n\n# What the old implementation had to walk on every call.\ntotal \u003d sum(\n    x.info[\"num_handles\"] or 0\n    for x in psutil.process_iter([\"num_handles\"])\n)\nprint(\"system: %s handles\" % total)\n\nt0 \u003d time.perf_counter()\nfor _ in range(50):\n    p.open_files()\nprint(\"open_files(): %.2f ms\" % ((time.perf_counter() - t0) / 50 * 1000))\n```\n\nWindows 10 (19045), same machine, same processes, master vs this branch.\nTwo\nruns taken hours apart, one with a busy desktop and one with an idle\none:\n\n|                          | master    | this PR |\n| ------------------------ | --------- | ------- |\n| run 1, whole call        | 235.82 ms | 0.59 ms |\n| run 1, C extension only  | 234.83 ms | 0.39 ms |\n| run 2, whole call        | 54.06 ms  | 0.37 ms |\n| run 2, C extension only  | 51.70 ms  | 0.34 ms |\n\nmaster\u0027s cost is proportional to the number of handles open system-wide,\nnot to the process being inspected, which is why it moves by 4.5x\nbetween two runs on the same machine.\n\n```\nmaster, run 1:\n  this process (pid 7656):        C extension  234.83 ms\n  a child with 3 open files:      C extension  232.91 ms\n\nthis branch, run 1:\n  this process (pid 6316):        C extension    0.39 ms\n  a child with 3 open files:      C extension    0.46 ms\n```"
    },
    {
      "commit": "335a5f0f5a4e8280f9640a75fd6fc0d3570306e0",
      "tree": "79ddfae2ee3316a13c1e8068a04f770029f0d959",
      "parents": [
        "e620864b8cbbcd540b10f8ea82409c02b84df3b9"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 14:19:32 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 14:19:32 2026"
      },
      "message": "Select tests with -k, file path args are ignored on UNC mounts\n"
    },
    {
      "commit": "e620864b8cbbcd540b10f8ea82409c02b84df3b9",
      "tree": "aeca8123c02313ebfc1aab0f2e7ca2677616cd14",
      "parents": [
        "2d0902923891a7ecead388dd43608ec163a04c00"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 14:19:31 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 14:19:31 2026"
      },
      "message": "Make test subprocesses import the psutil under test\n"
    },
    {
      "commit": "2d0902923891a7ecead388dd43608ec163a04c00",
      "tree": "2819bf580efbd3de1547d859b449262fde4ffff6",
      "parents": [
        "6452774439a8807ce53b07373d0df04b40668171"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 14:19:25 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 14:19:25 2026"
      },
      "message": "Skip or relax tests failing on windows\n"
    },
    {
      "commit": "6452774439a8807ce53b07373d0df04b40668171",
      "tree": "2ee1ef6f0bedf7f78ad289457b2d5c93ac2f3f12",
      "parents": [
        "0fb7a75a3d01e115c0d1f0c69beaae2545c9ba7c"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 11:45:41 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jul 30 11:45:41 2026"
      },
      "message": "[Windows] drop Vista, 7, 8, Server 2008-2012. Set min version to Windows 10 (#2931)\n\nFixes:\n- https://github.com/giampaolo/psutil/issues/2893"
    },
    {
      "commit": "0fb7a75a3d01e115c0d1f0c69beaae2545c9ba7c",
      "tree": "059b22ef187213b4131f2e8ed9f275db3b3eedcd",
      "parents": [
        "f9c789d40db25b9c1a9c6c044d8b68fda975347d"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 10:10:09 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 10:10:09 2026"
      },
      "message": "CI: give macOS builds their own lane to save some time\n"
    },
    {
      "commit": "f9c789d40db25b9c1a9c6c044d8b68fda975347d",
      "tree": "afdf733d5ed57c1028d2304f96c2278c3b1978ed",
      "parents": [
        "4f0e10bee99803bb6466a5bfccd682ffa2275fc5"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 07:57:54 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 07:57:54 2026"
      },
      "message": "print_downloads.py: report os/architecture of who downloads the .tar.gz\n"
    },
    {
      "commit": "4f0e10bee99803bb6466a5bfccd682ffa2275fc5",
      "tree": "ea71d3eb1097ac4771f7e3222a4fe2fbf586ed23",
      "parents": [
        "a714584286b0e1424a9e3e368ff926fb82b3cb38"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 00:52:57 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 00:52:57 2026"
      },
      "message": "Add PSUTIL_BUILD_JOBS env var, to control the number of CPUs on build\n"
    },
    {
      "commit": "a714584286b0e1424a9e3e368ff926fb82b3cb38",
      "tree": "d4e6a5d08fa7b5b6f02993a85fc4d62f725b4734",
      "parents": [
        "48387a9245cc2ac47af5a7f241273c8ccdbda21f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Thu Jul 30 00:24:45 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jul 30 00:24:45 2026"
      },
      "message": "Rework install-sysdeps.sh + source install docs (#2930)\n\n- `install-sysdeps.sh` now installs only what\u0027s needed to compile psutil\n(faster).\n- Added Fedora to `install-sysdeps.sh`\n- FreeBSD installed gcc (7 packages, 503 MiB) that nothing used: base cc\nis clang, and that\u0027s what python uses.\n- setup.py: better error message link to `install-sysdeps.sh` script\n- install.rst and devguide.rst were restructured"
    },
    {
      "commit": "48387a9245cc2ac47af5a7f241273c8ccdbda21f",
      "tree": "1d793c4587ae7820b7fd3c18f1519a03b6e5b3ba",
      "parents": [
        "80895286583ace0e84925d11b5ecf40a7f1ebc4d"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 17:59:56 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 17:59:56 2026"
      },
      "message": "[NetBSD, OpenBSD] process `num_fds()` didn\u0027t change + `open_files()` returned empty list (#2929)\n\n- [NetBSD]: `Process.num_fds` returned a wrong, system-wide number which\ndidn\u0027t change when the process opened a file. `KERN_FILE` is the old\nsysctl node and ignores the PID; `KERN_FILE2` is the one to use.\n- :gh:2929, [NetBSD], [OpenBSD]: `Process.open_files` always returned an\nempty list. We asked the kernel for 0 entries, so it copied none out."
    },
    {
      "commit": "80895286583ace0e84925d11b5ecf40a7f1ebc4d",
      "tree": "d67c1f4367465abf5e453271fe3c909b4f475c37",
      "parents": [
        "7ac7feaa64b4b6706aad01ddb50e9eea3fc30400"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 15:02:02 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 15:02:02 2026"
      },
      "message": "CI: parallelize `make lint-all` and `make check-dist` + add cache for dprint (#2928)\n\nParallelize make lint-all, make check-dist, use cache for dprint\n\n- `make check-dist` before: 6.6s, now: 3.1s\n- `make lint-all` before: 2.6s, now: 0.8s\n- 3.2s saved for the missing dprint installation on hot cache\n\nSo we save around 7 secs on each CI run"
    },
    {
      "commit": "7ac7feaa64b4b6706aad01ddb50e9eea3fc30400",
      "tree": "4e9b93d453cc3482b966fda1a773c24549413029",
      "parents": [
        "5d7729ce9cebe4aa9d383702a2a96367b5d88595"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 14:01:58 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 14:01:58 2026"
      },
      "message": "CI: install deps via uv (#2927)\n\nWhen uv is available (Linux, Windows, macOS) CI now uses `uv` to install\ndeps, else it falls back on `pip` (BSD, SunOS, AIX).\nSpeedup\n\n\n| workflow | job | platform | master (pip) | ci-speedup (uv) | Δ |\n|---|---|---|---|---|---|\n| build | `linters` | ubuntu | 7.31s | 0.20s | −7.1s (37×) |\n| build | `merge-and-check-dist` | ubuntu | 11.78s | 0.68s | −11.1s\n(17×) |\n| build | test matrix ×6 | win/mac/linux | — | — | 0 |\n| bsd | freebsd / netbsd / openbsd | BSD | pip | pip | 0 |\n| sunos | sunos | illumos | pip | pip | 0 |\n| docs | `build` | ubuntu | 28.01s | not yet run | est. −27s |\n| docs | `test-online` | ubuntu | 21.03s | not yet run | est. −20s |"
    },
    {
      "commit": "5d7729ce9cebe4aa9d383702a2a96367b5d88595",
      "tree": "67e3910fe1fded6a4635b7b266d11eb1e90b11ab",
      "parents": [
        "6a980593335830046530fc10363463eca4e0237b"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 13:09:33 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 13:09:33 2026"
      },
      "message": "Fix occasional win failure due to missing METH_NOARGS\n"
    },
    {
      "commit": "6a980593335830046530fc10363463eca4e0237b",
      "tree": "2d84ffc0623a40341bb9712c01179ac23e3ba2b7",
      "parents": [
        "7562951bd5334ace804e48a164535556c0ab5283"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 09:03:37 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 09:03:37 2026"
      },
      "message": "Try to fix flaky TestPopen test\n"
    },
    {
      "commit": "7562951bd5334ace804e48a164535556c0ab5283",
      "tree": "dde59d82c41eb9adbababc667987fe0708fdbe5b",
      "parents": [
        "3132bbbe72f2d6b4fd1a33c09dc2f16a79799938"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 08:48:26 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 08:48:26 2026"
      },
      "message": "Update changelog.rst\n"
    },
    {
      "commit": "3132bbbe72f2d6b4fd1a33c09dc2f16a79799938",
      "tree": "af7d2e20e7723997aa6dbfd82d33401c1a8be781",
      "parents": [
        "4e482f3bc6cc2da6fcbefca96be339ab70c61b2b"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Wed Jul 29 08:46:57 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 08:46:57 2026"
      },
      "message": "Compile C sources in parallel (#2925)\n\n## About\n\n`setup.py` compiles psutil\u0027s C files one file at a time, serially. This\nPR overrides `setuptools` internals to enable parallel compilation. On\nLinux we have 17 .c files, on Windows we have 23, so this sort of split\nin terms of workload can really payoff.\n\n## The speedup\n\nMeasured by observing GitHub CI runs before/after the patch:\n\n| platform         | before | after | speedup |\n|:-----------------|-------:|------:|--------:|\n| ubuntu-24.04-arm |  1.28s | 0.36s |   3.59x |\n| ubuntu-latest    |  1.17s | 0.39s |   3.02x |\n| macos-15-intel   |  8.78s | 2.99s |   2.93x |\n| macos-15 (arm64) |  3.40s | 1.22s |   2.79x |\n| Solaris          |  3.23s | 1.34s |   2.41x |\n| FreeBSD          |  1.56s | 0.66s |   2.36x |\n| NetBSD           |  1.82s | 0.82s |   2.21x |\n| OpenBSD          |  3.69s | 1.71s |   2.16x |\n| windows-11-arm   |  9.25s | 4.42s |   2.09x |\n| windows-2025     |  9.59s | 4.94s |   1.94x |\n\n## Impact\n\nSince we distribute wheels for Linux, Windows and macOS, who will be\naffected by this change are people installing psutil from sources,\nmeaning BSD, SunOS, AIX users + all the Linux users running exotic\narchitectures.\n\n\n[scripts/internal/print_downloads.py](https://github.com/giampaolo/psutil/blob/4e482f3b/scripts/internal/print_downloads.py)\ntells us that source installations are 2% of the total, aka 5 millions\nper month. Those 5 millions are the ones who will benefit from this. And\nalso our CI run gets faster.\n\n```\n$ python3 scripts/internal/print_downloads.py\npsutil downloads in the last 30 days\nWheel types                           Downloads        %\n--------------------------------------------------------\nwheel (abi3)                        226,458,056    96.91\nsdist (built from source)             5,089,248     2.18\nwheel (version specific)              1,624,025     0.69\nwheel (free-threaded)                   504,456     0.22\n```"
    },
    {
      "commit": "4e482f3bc6cc2da6fcbefca96be339ab70c61b2b",
      "tree": "f0a369aa3e29c5e8323258c6629d479745dcffd9",
      "parents": [
        "7859a1514bbf4933032fc37d0ec76d710bf95ef9"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 23:22:34 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 23:22:34 2026"
      },
      "message": "[Windows] fetch `Process.status() via `oneshot()` (#2923)\n\n`Process.status()` calls proc_is_suspended(), which fetches the whole\nsystem process table via `NtQuerySystemInformation()` and walks the\nprocess\u0027 threads looking for one that isn\u0027t suspended.\n\n`proc_oneshot()` already fetches that same table, and already walks that\nsame thread array to sum context switches. So `status()` can run under\n`oneshot()` and take advantage of the cache. The speedup will touch\nusers of ``Process.as_dict()`, `ppid()` invoked under `oneshot()` and\n`process_iter().\n\nThis is the same thing I did for page_faults() in fd02d0fe.\n\n- Before the patch: regular: 2.555 secs, oneshot: 1.291 secs (+1.98x)\n- After the patch: regular: 2.250 secs, oneshot: 0.576 secs (+3.91x)"
    },
    {
      "commit": "7859a1514bbf4933032fc37d0ec76d710bf95ef9",
      "tree": "b1bf2441d98f88644868b0d4102e1008a2af1dd8",
      "parents": [
        "48ebed552f1b0266b6cf537e5214e6ab2f8ce8f9"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 22:48:21 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 22:48:21 2026"
      },
      "message": "Doc: audit oneshot() grouped APIs\n"
    },
    {
      "commit": "48ebed552f1b0266b6cf537e5214e6ab2f8ce8f9",
      "tree": "64b6e6eb804cc0c56962e51bd4f415a11e5c1e0b",
      "parents": [
        "3c846307a3132a8d28bb17849355eab740b5ad5d"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 22:31:23 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 22:31:23 2026"
      },
      "message": "[Windows] speedup `Process.ppid()` (#2922)\n\n## About\n\nThis is similar to:\n- https://github.com/giampaolo/psutil/pull/2919\n- https://github.com/giampaolo/psutil/pull/2920\n\n`Process.ppid()` fetches the whole system process table via\n`NtQuerySystemInformation()` + `SystemProcessInformation`, just to read\none field of one entry.\n\nWe can get the PID directly via `NtQueryInformationProcess()` +\n`ProcessBasicInformation`, which only needs a process handle.\n\nSince it needs a handle it can fail with `AccessDenied`, in which case\nwe fall back to `ppid_map()` as before. Same dual-implementation pattern\nas `num_handles()` and `memory_info()`.\n\n`parent()` and `parents()` utility methods depend on `ppid()`, so they\nalso get the speedup.\n\n## The speedup\n\nCalling ``ppid()`` 1000 times:\n\n```python\nimport psutil, time\n\np \u003d psutil.Process()\nstarted \u003d time.monotonic()\nfor x in range(1000):\n    p._ppid \u003d None  # ppid() is cached on Windows\n    p.ppid()\nprint(f\"completed in {(time.monotonic() - started):.4f} secs\")  # noqa\n```\n\n- Before the patch: **0.5322 secs**\n- After the patch: **0.0092 secs**\n\n...around **58x faster**. On Windows 11 ARM64 it\u0027s 0.7201 -\u003e 0.0073\nsecs, so around **99x faster**."
    },
    {
      "commit": "3c846307a3132a8d28bb17849355eab740b5ad5d",
      "tree": "ea4ca1871d93f08366aa19e036bde07bf7d20edc",
      "parents": [
        "60809d060a6d5aee9972e2a450986c3d40f2ce9c"
      ],
      "author": {
        "name": "Frank Dana",
        "email": "ferdnyc@gmail.com",
        "time": "Tue Jul 28 21:55:31 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 21:55:31 2026"
      },
      "message": "doc: Reformat the oneshot speedup-groups information without the table layout (#2884)\n\nThis is a replacement PR for #2248. The modifications are largely\nunchanged, but they target the updated documentation path and\nincorporate any source changes made since the original PR was opened.\n\n## Summary\n\n- OS: All\n- Bug fix: no\n- Type: doc\n- Replaces: #2248\n\n## Description\n\nIMHO the table layout used for the list of methods sped up by\n`oneshot()` was not really working. Horizontal alignment of various\nmethods meant nothing, so having the platforms side-by-side also meant\nnothing. Blank rows were hard to spot, making the groupings unclear.\nBasically, it was just a list of groups-of-methods, formatted so it\u0027s\ndifficult to read on narrow screens.\n\nThis PR folds up each column of the table into a subsection of the\nperformance document, titled by platform. Each platform section contains\nan unordered list of one to three items representing a group of methods,\nwhere each group (list item) is a comma-separated list of method names.\n\n### Other/Related changes\n\n* Rewrote the introduction to the section so that it makes reference to\nthe new format of the information.\n* Replaced the `x` characters in the speedup figures (e.g. \u0027+2.0x\u0027) with\nUnicode multiplication glyphs (i.e. \u0027+2.0×\u0027)\n\n### Sample screenshot\n\n\u003cimg width\u003d\"742\" height\u003d\"846\" alt\u003d\"image\"\nsrc\u003d\"https://github.com/user-attachments/assets/80345264-fa29-4d80-a4ef-5c59556edf8b\"\n/\u003e\n\n---------\n\nCo-authored-by: Giampaolo Rodola \u003cg.rodola@gmail.com\u003e"
    },
    {
      "commit": "60809d060a6d5aee9972e2a450986c3d40f2ce9c",
      "tree": "3baa8737826ea83ddf4bd2328401caec211587b6",
      "parents": [
        "fd02d0fe49f1e02f5fd4ed9d2ad57bc5556d0924"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 21:48:21 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 21:48:21 2026"
      },
      "message": "Fix \"last updated\" doc test failing due to PR merge\n"
    },
    {
      "commit": "fd02d0fe49f1e02f5fd4ed9d2ad57bc5556d0924",
      "tree": "b9b120ad4f6e088a2ae31378bb5afa9968407d12",
      "parents": [
        "b285034a8de397935aa04b541f61ad2414355649"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 20:30:42 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 20:30:42 2026"
      },
      "message": "Windows: get page_faults() via oneshot() (faster)\n"
    },
    {
      "commit": "b285034a8de397935aa04b541f61ad2414355649",
      "tree": "583820bde0b3762b1656040bf4e5b8513c9d75b8",
      "parents": [
        "eb1783dfe914c1a7a7e1e8ef501dd8b473d39b6f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 20:19:54 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 20:19:54 2026"
      },
      "message": " [Windows] speedup `ppid_map()`, `children()`, `ppid()` (#2920)\n\n## About\n\nThis is similar to:\n- https://github.com/giampaolo/psutil/pull/2919\n\n`ppid_map()` (used internally by `Process.ppid()` and\n`Process.children()`) use `CreateToolhelp32Snapshot()`, which snapshots\nall processes system-wide, then walks the snapshot with\n`Process32First()` / `Process32Next()` to read 2 fields per entry: the\nPID and its parent PID.\n\n`NtQuerySystemInformation()` + `SystemProcessInformation` already gives\nboth. So same story as #2919: I never noticed the info was already\nthere, for free.\n\n## The speedup\n\nCalling ppid_map() 1000 times:\n\n```python\nimport psutil, time\n\np \u003d psutil.Process()\nstarted \u003d time.monotonic()\nfor x in range(1000):\n    p.children()\nprint(f\"completed in {(time.monotonic() - started):.4f} secs\")  # noqa\n```\n\n- Before the patch 1.5325 secs\n- After the patch in 0.4452 secs\n\n...around **3.5x faster**."
    },
    {
      "commit": "eb1783dfe914c1a7a7e1e8ef501dd8b473d39b6f",
      "tree": "bc7426e1d8ced7b8d57b676e0da260d0f193641e",
      "parents": [
        "ea641061af4409478282c3dbcefcd48b93156c55"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 19:02:14 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 19:02:14 2026"
      },
      "message": "[Windows] drastically speedup `Process.threads()` (#2919)\n\n## About\n\nCurrent `Process.threads()` implementation relies on\n`CreateToolhelp32Snapshot()`, which takes a snapshot of all threads for\nall processes, system-wide. It then walks that snapshot with\n`Thread32First()` / `Thread32Next()` to match the process PID, and for\nevery thread that matches calls `OpenThread()` and `GetThreadTimes()`.\n\nAll of this can be avoided, simply by using `NtQuerySystemInformation()`\n+ `SystemProcessInformation`, which iterates over all PIDs instead of\nall threads (which are a lot more).\n\nEach process entry already has the threads inline. Funny thing: the\nmachinery for doing this was already in place to fetch other process\ninfo. I just never noticed we can also fetch threads this way.\n\n## The speedup\n\nCalling `threads()` 1000 times:\n\n```python\nimport psutil, time\n\np \u003d psutil.Process()\nstarted \u003d time.monotonic()\nfor x in range(1000):\n    p.threads()\nprint(f\"completed in {(time.monotonic() - started):.4f} secs\")  # noqa\n```\n\nThe speedup:\n\n- Before the patch:  **12.7260** secs\n- After the patch: **0.5197** secs\n\n**24.5×** faster!\n\n## Extra\n\n- `OpenThread()` failures were skipped in case the thread disappeared\n(race condition), but that could also mean we skipped `AccessDenied`. So\nthreads() before could silently return an incomplete list for processes\nowned by another user.\n- Enumerating a thread and reading its times were 2 separate steps. A\nthread exiting in between either vanished from the result or made\nGetThreadTimes() fail and raise. Now it\u0027s one consistent snapshot."
    },
    {
      "commit": "ea641061af4409478282c3dbcefcd48b93156c55",
      "tree": "57deb9a2fc145d6e50ff6f9de90fae78e2c57962",
      "parents": [
        "72f755605490e1ba0d252a6ee64b12528970564f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 10:38:43 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 10:38:43 2026"
      },
      "message": "Try to make test_cmdline less flaky\n"
    },
    {
      "commit": "72f755605490e1ba0d252a6ee64b12528970564f",
      "tree": "87c1750122bf44142d72b89300e6556632392adb",
      "parents": [
        "48f1fd85884494492a357889a58df3aecd4db195"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 10:21:16 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 10:21:16 2026"
      },
      "message": "Try to fix flaky test_against_ifconfig on Linux\n"
    },
    {
      "commit": "48f1fd85884494492a357889a58df3aecd4db195",
      "tree": "6312d46f9b25d66b6521082fe854d2e6cc5ff2a7",
      "parents": [
        "af2116aeecf1a4247a1a549a8e5e679da50fa93f"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 10:15:12 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 10:15:12 2026"
      },
      "message": "Invalidate cache every time build.yml or pyproject.toml change.\n\nAlso remove Defender MSVC trick on Windows (it\u0027s useless)\n"
    },
    {
      "commit": "af2116aeecf1a4247a1a549a8e5e679da50fa93f",
      "tree": "ef36c602be6a6b049bb0ed87c4b4ba2d432e446e",
      "parents": [
        "c8a5b214c51f6b0414538f345ac83b482139f9c6"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Tue Jul 28 08:22:44 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 08:22:44 2026"
      },
      "message": "CI: use uv in cibuildwheel (#2918)\n\ncibuildwheel now creates venvs and installs packages with uv instead of\npip / virtualenv. Gain:\n\n| Job | Master | uv | Delta | Change |\n|---|---:|---:|---:|---:|\n| `windows-2025`, AMD64 | 306s | 241s | -65s | -21% |\n| `windows-11-arm`, ARM64 | 301s | 264s | -37s | -12% |\n| `ubuntu-latest`, x86_64 | 168s | 136s | -32s | -19% |\n| `macos-15`, arm64 | 133s | 104s | -29s | -22% |\n| `ubuntu-24.04-arm`, aarch64 | 147s | 124s | -23s | -16% |\n| `macos-15-intel`, x86_64 | 152s | 142s | -10s | -7% |\n| `merge-and-check-dist` | 41s | 36s | -5s | -12% |\n| `linters` | 25s | 22s | -3s | -12% |\n| **Total runner time** | **1273s** | **1069s** | **-204s** | **-16%** |"
    },
    {
      "commit": "c8a5b214c51f6b0414538f345ac83b482139f9c6",
      "tree": "fd3a3389f813404ae7c6c5f759cc37b3157b9f4e",
      "parents": [
        "61a217421c71c2e9f131923170a3fd03b965969d"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Tue Jul 28 00:08:15 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 00:08:15 2026"
      },
      "message": "Bump the github-actions group with 2 updates (#2917)"
    },
    {
      "commit": "61a217421c71c2e9f131923170a3fd03b965969d",
      "tree": "388667f3511a307b9e679e538299948c7a4d975a",
      "parents": [
        "300463a1cac0fa7269caf13df17e0d8159f37ff0"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Jul 27 22:55:08 2026"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 27 22:55:08 2026"
      },
      "message": "Upgrade cibuildwheel to 4.1.1, drop cp313t wheels (#2916)\n\ncibuildwheel 4.0 removed `cp313t` after manylinux stopped building the\nimages. Keeping `cp313t` wheels means staying on 3.x for *all* our Linux\nwheels. So we drop them instead.\n\n3.8 is no longer a build target. The shipped abi3 wheel is now produced\nby 3.9. The tag stays `cp38-abi3`.\n\nFixes:\n- #2915"
    },
    {
      "commit": "300463a1cac0fa7269caf13df17e0d8159f37ff0",
      "tree": "1a5c120443f698c7d19c4a494790b47afde5ab7b",
      "parents": [
        "73ff792be6451054ebaafee1e241b80f7b1dd4bb"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Jul 27 19:23:35 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Jul 27 19:23:35 2026"
      },
      "message": "test_winservices: only check syntax; running it sporadically times out on CI\n"
    },
    {
      "commit": "73ff792be6451054ebaafee1e241b80f7b1dd4bb",
      "tree": "d6ab63b6514fedec8f194c22932f00d5843d3bb7",
      "parents": [
        "371b42afd6c84176503485ec1cb90458ad598ccb"
      ],
      "author": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Jul 27 19:07:14 2026"
      },
      "committer": {
        "name": "Giampaolo Rodola",
        "email": "g.rodola@gmail.com",
        "time": "Mon Jul 27 19:07:14 2026"
      },
      "message": "MacOS: set floor for published wheels to 10.15 (was 10.9); fixes #2914\n"
    }
  ],
  "next": "371b42afd6c84176503485ec1cb90458ad598ccb"
}
