gh-137512: Add new constants in the resource module (GH-137513)

* RLIMIT_NTHR
* RLIMIT_THREADS
* RLIMIT_UMTXP
* RLIM_SAVED_CUR
* RLIM_SAVED_MAX

* Document RLIMIT_PIPEBUF. Other doc fixes.
diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst
index 0421b35..ea75c8b 100644
--- a/Doc/library/resource.rst
+++ b/Doc/library/resource.rst
@@ -57,6 +57,16 @@
       Previously, it could be negative, such as -1 or -3.
 
 
+.. data:: RLIM_SAVED_CUR
+.. data:: RLIM_SAVED_MAX
+
+   Constants used to represent the soft and hard limit values if they
+   cannot be represented in the ``rlim_t`` value in C.
+   Can be equal to :data:`RLIM_INFINITY`.
+
+   .. versionadded:: next
+
+
 .. function:: getrlimit(resource)
 
    Returns a tuple ``(soft, hard)`` with the current soft and hard limits of
@@ -181,8 +191,9 @@
 .. data:: RLIMIT_VMEM
 
    The largest area of mapped memory which the process may occupy.
+   Usually an alias of :const:`RLIMIT_AS`.
 
-   .. availability:: FreeBSD >= 11.
+   .. availability:: Solaris, FreeBSD, NetBSD.
 
 
 .. data:: RLIMIT_AS
@@ -235,16 +246,18 @@
 
    .. versionadded:: 3.4
 
+
 .. data:: RLIMIT_SBSIZE
 
    The maximum size (in bytes) of socket buffer usage for this user.
    This limits the amount of network memory, and hence the amount of mbufs,
    that this user may hold at any time.
 
-   .. availability:: FreeBSD.
+   .. availability:: FreeBSD, NetBSD.
 
    .. versionadded:: 3.4
 
+
 .. data:: RLIMIT_SWAP
 
    The maximum size (in bytes) of the swap space that may be reserved or
@@ -254,18 +267,20 @@
    `tuning(7) <https://man.freebsd.org/cgi/man.cgi?query=tuning&sektion=7>`__
    for a complete description of this sysctl.
 
-   .. availability:: FreeBSD.
+   .. availability:: FreeBSD >= 8.
 
    .. versionadded:: 3.4
 
+
 .. data:: RLIMIT_NPTS
 
    The maximum number of pseudo-terminals created by this user id.
 
-   .. availability:: FreeBSD.
+   .. availability:: FreeBSD >= 8.
 
    .. versionadded:: 3.4
 
+
 .. data:: RLIMIT_KQUEUES
 
    The maximum number of kqueues this user id is allowed to create.
@@ -274,6 +289,46 @@
 
    .. versionadded:: 3.10
 
+
+.. data:: RLIMIT_NTHR
+
+   The maximum number of threads for this user id, not counting the main
+   and kernel threads.
+
+   .. availability:: NetBSD >= 7.0.
+
+   .. versionadded:: next
+
+
+.. data:: RLIMIT_PIPEBUF
+
+   The maximum total size of in-kernel buffers for bi-directional pipes/fifos
+   that this user id is allowed to consume.
+
+   .. availability:: FreeBSD >= 14.2.
+
+   .. versionadded:: next
+
+
+.. data:: RLIMIT_THREADS
+
+   The maximum number of threads each process can create.
+
+   .. availability:: AIX.
+
+   .. versionadded:: next
+
+
+.. data:: RLIMIT_UMTXP
+
+   The limit of the number of process-shared Posix thread library objects
+   allocated by user id.
+
+   .. availability:: FreeBSD >= 11.
+
+   .. versionadded:: next
+
+
 Resource Usage
 --------------
 
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index eb073ca..43c40e4 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -312,6 +312,15 @@
   the resulting path can be missing but it will be free of symlinks.
   (Contributed by Petr Viktorin for :cve:`2025-4517`.)
 
+resource
+--------
+
+* Add new constants: :data:`~resource.RLIMIT_NTHR`,
+  :data:`~resource.RLIMIT_UMTXP`, :data:`~resource.RLIMIT_THREADS`,
+  :data:`~resource.RLIM_SAVED_CUR`, and :data:`~resource.RLIM_SAVED_MAX`.
+  (Contributed by Serhiy Storchaka in :gh:`137512`.)
+
+
 shelve
 ------
 
diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py
index 7391ce5..f73914b 100644
--- a/Lib/test/test_resource.py
+++ b/Lib/test/test_resource.py
@@ -200,6 +200,15 @@ def test_pagesize(self):
         self.assertIsInstance(pagesize, int)
         self.assertGreaterEqual(pagesize, 0)
 
+    def test_contants(self):
+        self.assertIsInstance(resource.RLIM_INFINITY, int)
+        if sys.platform.startswith(('freebsd', 'solaris', 'sunos', 'aix')):
+            self.assertHasAttr(resource, 'RLIM_SAVED_CUR')
+            self.assertHasAttr(resource, 'RLIM_SAVED_MAX')
+        if hasattr(resource, 'RLIM_SAVED_CUR'):
+            self.assertIsInstance(resource.RLIM_SAVED_CUR, int)
+            self.assertIsInstance(resource.RLIM_SAVED_MAX, int)
+
     @unittest.skipUnless(sys.platform in ('linux', 'android'), 'Linux only')
     def test_linux_constants(self):
         for attr in ['MSGQUEUE', 'NICE', 'RTPRIO', 'RTTIME', 'SIGPENDING']:
@@ -207,7 +216,7 @@ def test_linux_constants(self):
                 self.assertIsInstance(getattr(resource, 'RLIMIT_' + attr), int)
 
     def test_freebsd_contants(self):
-        for attr in ['SWAP', 'SBSIZE', 'NPTS']:
+        for attr in ['SWAP', 'SBSIZE', 'NPTS', 'UMTXP', 'VMEM', 'PIPEBUF']:
             with contextlib.suppress(AttributeError):
                 self.assertIsInstance(getattr(resource, 'RLIMIT_' + attr), int)
 
diff --git a/Misc/NEWS.d/next/Library/2025-08-07-15-07-44.gh-issue-137512.j2or5h.rst b/Misc/NEWS.d/next/Library/2025-08-07-15-07-44.gh-issue-137512.j2or5h.rst
new file mode 100644
index 0000000..fc67913
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-08-07-15-07-44.gh-issue-137512.j2or5h.rst
@@ -0,0 +1,4 @@
+Add new constants in the :mod:`resource` module:
+:data:`~resource.RLIMIT_NTHR`, :data:`~resource.RLIMIT_UMTXP`,
+:data:`~resource.RLIMIT_PIPEBUF`, :data:`~resource.RLIMIT_THREADS`,
+:data:`~resource.RLIM_SAVED_CUR`, and :data:`~resource.RLIM_SAVED_MAX`.
diff --git a/Modules/resource.c b/Modules/resource.c
index 2637302..a463355 100644
--- a/Modules/resource.c
+++ b/Modules/resource.c
@@ -522,9 +522,38 @@ resource_exec(PyObject *module)
     ADD_INT(module, RLIMIT_KQUEUES);
 #endif
 
+#ifdef RLIMIT_NTHR
+    ADD_INT(module, RLIMIT_NTHR);
+#endif
+
+#ifdef RLIMIT_THREADS
+    ADD_INT(module, RLIMIT_THREADS);
+#endif
+
+#ifdef RLIMIT_UMTXP
+    ADD_INT(module, RLIMIT_UMTXP);
+#endif
+
+#ifdef RLIMIT_PIPEBUF
+    ADD_INT(module, RLIMIT_PIPEBUF);
+#endif
+
     if (PyModule_Add(module, "RLIM_INFINITY", rlim2py(RLIM_INFINITY)) < 0) {
         return -1;
     }
+
+#ifdef RLIM_SAVED_CUR
+    if (PyModule_Add(module, "RLIM_SAVED_CUR", rlim2py(RLIM_SAVED_CUR)) < 0) {
+        return -1;
+    }
+#endif
+
+#ifdef RLIM_SAVED_MAX
+    if (PyModule_Add(module, "RLIM_SAVED_MAX", rlim2py(RLIM_SAVED_MAX)) < 0) {
+        return -1;
+    }
+#endif
+
     return 0;
 
 #undef ADD_INT