The branch main has been updated by bnovkov:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=aae23170c8b5ac320dbf9c5f6cec05bea0b4b62f

commit aae23170c8b5ac320dbf9c5f6cec05bea0b4b62f
Author:     Bojan Novković <bnov...@freebsd.org>
AuthorDate: 2024-09-08 15:51:46 +0000
Commit:     Bojan Novković <bnov...@freebsd.org>
CommitDate: 2025-07-27 16:31:48 +0000

    libutil: Move cpuset(1) domain policy parsing code into libutil
    
    cpuset(1) implements a domainset(9) policy parser that is used to
    translate a <policy>:<domain_list> string into a domainset_t mask
    and a valid domainset policy. This change moves the domainset parsing
    code into a new cpuset.c function - 'domainset_parselist'.
    
    The existing cpuset.c code was refactored into a generalized list
    parsing function which is now used to parse both CPU sets and domain
    sets. This is the same approach used in cpuset(1).
    
    Reviewed by:    markj, ziaee (manpages)
    Differential Revision:  https://reviews.freebsd.org/D46607
---
 bin/cpuset/Makefile   |   2 +-
 bin/cpuset/cpuset.c   | 153 +-------------------------------------------------
 lib/libutil/Makefile  |   1 +
 lib/libutil/cpuset.3  |  51 ++++++++++++++---
 lib/libutil/cpuset.c  |  98 ++++++++++++++++++++++++++++----
 lib/libutil/libutil.h |   8 ++-
 6 files changed, 140 insertions(+), 173 deletions(-)

diff --git a/bin/cpuset/Makefile b/bin/cpuset/Makefile
index d6f58db62901..639dd9812171 100644
--- a/bin/cpuset/Makefile
+++ b/bin/cpuset/Makefile
@@ -1,6 +1,6 @@
 PROG=   cpuset
 
-LIBADD=        jail
+LIBADD=        jail util
 
 SYMLINKS+=     ../..${BINDIR}/cpuset   /usr/bin/cpuset
 
diff --git a/bin/cpuset/cpuset.c b/bin/cpuset/cpuset.c
index 82ffcaeec252..7416e100a3c6 100644
--- a/bin/cpuset/cpuset.c
+++ b/bin/cpuset/cpuset.c
@@ -43,6 +43,7 @@
 #include <err.h>
 #include <errno.h>
 #include <jail.h>
+#include <libutil.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -69,154 +70,6 @@ static cpuwhich_t which;
 
 static void usage(void) __dead2;
 
-struct numa_policy {
-       const char      *name;
-       int             policy;
-};
-
-static struct numa_policy policies[] = {
-       { "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
-       { "rr", DOMAINSET_POLICY_ROUNDROBIN },
-       { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
-       { "ft", DOMAINSET_POLICY_FIRSTTOUCH },
-       { "prefer", DOMAINSET_POLICY_PREFER },
-       { "interleave", DOMAINSET_POLICY_INTERLEAVE},
-       { "il", DOMAINSET_POLICY_INTERLEAVE},
-       { NULL, DOMAINSET_POLICY_INVALID }
-};
-
-static void printset(struct bitset *mask, int size);
-
-static void
-parselist(char *list, struct bitset *mask, int size)
-{
-       enum { NONE, NUM, DASH } state;
-       int lastnum;
-       int curnum;
-       char *l;
-
-       state = NONE;
-       curnum = lastnum = 0;
-       for (l = list; *l != '\0';) {
-               if (isdigit(*l)) {
-                       curnum = atoi(l);
-                       if (curnum >= size)
-                               errx(EXIT_FAILURE,
-                                   "List entry %d exceeds maximum of %d",
-                                   curnum, size - 1);
-                       while (isdigit(*l))
-                               l++;
-                       switch (state) {
-                       case NONE:
-                               lastnum = curnum;
-                               state = NUM;
-                               break;
-                       case DASH:
-                               for (; lastnum <= curnum; lastnum++)
-                                       BIT_SET(size, lastnum, mask);
-                               state = NONE;
-                               break;
-                       case NUM:
-                       default:
-                               goto parserr;
-                       }
-                       continue;
-               }
-               switch (*l) {
-               case ',':
-                       switch (state) {
-                       case NONE:
-                               break;
-                       case NUM:
-                               BIT_SET(size, curnum, mask);
-                               state = NONE;
-                               break;
-                       case DASH:
-                               goto parserr;
-                               break;
-                       }
-                       break;
-               case '-':
-                       if (state != NUM)
-                               goto parserr;
-                       state = DASH;
-                       break;
-               default:
-                       goto parserr;
-               }
-               l++;
-       }
-       switch (state) {
-               case NONE:
-                       break;
-               case NUM:
-                       BIT_SET(size, curnum, mask);
-                       break;
-               case DASH:
-                       goto parserr;
-       }
-       return;
-parserr:
-       errx(EXIT_FAILURE, "Malformed list %s", list);
-}
-
-static void
-parsecpulist(char *list, cpuset_t *mask)
-{
-
-       if (strcasecmp(list, "all") == 0) {
-               if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
-                   sizeof(*mask), mask) != 0)
-                       err(EXIT_FAILURE, "getaffinity");
-               return;
-       }
-       parselist(list, (struct bitset *)mask, CPU_SETSIZE);
-}
-
-/*
- * permissively parse policy:domain list
- * allow:
- *     round-robin:0-4         explicit
- *     round-robin:all         explicit root domains
- *     0-4                     implicit root policy
- *     round-robin             implicit root domains
- *     all                     explicit root domains and implicit policy
- */
-static void
-parsedomainlist(char *list, domainset_t *mask, int *policyp)
-{
-       domainset_t rootmask;
-       struct numa_policy *policy;
-       char *l;
-       int p;
-
-       /*
-        * Use the rootset's policy as the default for unspecified policies.
-        */
-       if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
-           sizeof(rootmask), &rootmask, &p) != 0)
-               err(EXIT_FAILURE, "getdomain");
-
-       l = list;
-       for (policy = &policies[0]; policy->name != NULL; policy++) {
-               if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
-                       p = policy->policy;
-                       l += strlen(policy->name);
-                       if (*l != ':' && *l != '\0')
-                               errx(EXIT_FAILURE, "Malformed list %s", list);
-                       if (*l == ':')
-                               l++;
-                       break;
-               }
-       }
-       *policyp = p;
-       if (strcasecmp(l, "all") == 0 || *l == '\0') {
-               DOMAINSET_COPY(&rootmask, mask);
-               return;
-       }
-       parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE);
-}
-
 static void
 printset(struct bitset *mask, int size)
 {
@@ -327,11 +180,11 @@ main(int argc, char *argv[])
                        break;
                case 'l':
                        lflag = 1;
-                       parsecpulist(optarg, &mask);
+                       cpuset_parselist(optarg, &mask);
                        break;
                case 'n':
                        nflag = 1;
-                       parsedomainlist(optarg, &domains, &policy);
+                       domainset_parselist(optarg, &domains, &policy);
                        break;
                case 'p':
                        pflag = 1;
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index 0639745d08fc..2d92c5ba1916 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -38,6 +38,7 @@ MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.3 ftime.3 
getlocalbase.3 \
        property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \
        _secure_path.3 trimdomain.3 uucplock.3 pw_util.3
 MAN+=  login.conf.5
+MLINKS+=cpuset.3 domainset_parselist.3
 MLINKS+=flopen.3 flopenat.3
 MLINKS+=kld.3 kld_isloaded.3 kld.3 kld_load.3
 MLINKS+=login_auth.3 auth_cat.3 login_auth.3 auth_checknologin.3
diff --git a/lib/libutil/cpuset.3 b/lib/libutil/cpuset.3
index be29d5309ef0..47dffd209ee6 100644
--- a/lib/libutil/cpuset.3
+++ b/lib/libutil/cpuset.3
@@ -22,21 +22,22 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd October 31, 2017
+.Dd June 24, 2025
 .Dt CPUSET 3
 .Os
 .Sh NAME
-.Nm cpuset_parselist
-.Nd utility functions for
-.Xr cpuset 2
-handling
+.Nm cpuset_parselist ,
+.Nm domainset_parselist
+.Nd utility functions for cpuset(2) handling
 .Sh LIBRARY
 .Lb libutil
 .Sh SYNOPSIS
 .In sys/cpuset.h
 .In libutil.h
 .Ft int
-.Fn cpuset_parselist "const char *cpu-list" "cpuset_t *mask"
+.Fn cpuset_parselist "const char *cpu_list" "cpuset_t *mask"
+.Ft int
+.Fn domainset_parselist "const char *domain_policy" "domainset_t *domain_mask" 
"int *policyp"
 .Sh DESCRIPTION
 The
 .Fn cpuset_parselist
@@ -52,6 +53,27 @@ numbers.
 A special list of
 .Dq all
 may be specified in which case the list includes all CPUs from the root set.
+.Pp
+The
+.Fn domainset_parselist
+function parses a
+.Xr domainset 9
+memory domain allocation policy
+specified by
+.Va domain_policy
+filling the
+.Va domain_mask
+and the
+.Va policyp .
+A valid
+.Va domain_policy
+is formatted as
+.Ar policy:domain-list .
+See the
+.Ar -n
+flag in
+.Xr cpuset 1
+for a list of valid domain policies.
 .Sh RETURN VALUES
 Return values can be the following
 .Bl -tag -width Er
@@ -60,19 +82,30 @@ The parsing was successful
 .It Dv CPUSET_PARSE_ERROR
 The
 .Va cpu-list
+or
+.Va domain-policy
 format is invalid
 .It Dv CPUSET_PARSE_GETAFFINITY
 The
 .Xr cpuset_getaffinity 2
 call has failed
 .It Dv CPUSET_PARSE_INVALID_CPU
-The number of supported CPUs has been exceeded.
+The number of supported CPUs or NUMA domains has been exceeded.
 The maximum number being
-.Va CPU_SETSIZE .
+.Va CPU_SETSIZE
+and
+.Va DOMAINSET_SETSIZE
+respectively.
+.It Dv CPUSET_PARSE_GETDOMAIN
+The
+.Xr cpuset_getdomain 2
+call has failed
 .El
 .Sh SEE ALSO
 .Xr cpuset 1 ,
 .Xr cpuset 2 ,
-.Xr cpuset 9
+.Xr numa 4 ,
+.Xr cpuset 9 ,
+.Xr domainset 9
 .Sh AUTHORS
 .An Jeffrey Roberson Aq Mt j...@freebsd.org
diff --git a/lib/libutil/cpuset.c b/lib/libutil/cpuset.c
index 3c374bfa6cac..d4840af7e175 100644
--- a/lib/libutil/cpuset.c
+++ b/lib/libutil/cpuset.c
@@ -27,34 +27,48 @@
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
+#define _WANT_FREEBSD_BITSET
+
 #include <sys/types.h>
 #include <sys/cpuset.h>
+#include <sys/domainset.h>
 
 #include <stdlib.h>
 #include <string.h>
 #include <libutil.h>
 #include <ctype.h>
 
-int
-cpuset_parselist(const char *list, cpuset_t *mask)
+struct numa_policy {
+       const char      *name;
+       int             policy;
+};
+
+static const struct numa_policy policies[] = {
+       { "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
+       { "rr", DOMAINSET_POLICY_ROUNDROBIN },
+       { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
+       { "ft", DOMAINSET_POLICY_FIRSTTOUCH },
+       { "prefer", DOMAINSET_POLICY_PREFER },
+       { "interleave", DOMAINSET_POLICY_INTERLEAVE},
+       { "il", DOMAINSET_POLICY_INTERLEAVE},
+       { NULL, DOMAINSET_POLICY_INVALID }
+};
+
+static int
+parselist(const char *list, struct bitset *mask, int size)
 {
        enum { NONE, NUM, DASH } state;
        int lastnum;
        int curnum;
        const char *l;
 
-       if (strcasecmp(list, "all") == 0) {
-               if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
-                   sizeof(*mask), mask) != 0)
-                       return (CPUSET_PARSE_GETAFFINITY);
-               return (CPUSET_PARSE_OK);
-       }
        state = NONE;
        curnum = lastnum = 0;
        for (l = list; *l != '\0';) {
                if (isdigit(*l)) {
                        curnum = atoi(l);
-                       if (curnum > CPU_SETSIZE)
+                       if (curnum >= size)
                                return (CPUSET_PARSE_INVALID_CPU);
                        while (isdigit(*l))
                                l++;
@@ -65,7 +79,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
                                break;
                        case DASH:
                                for (; lastnum <= curnum; lastnum++)
-                                       CPU_SET(lastnum, mask);
+                                       BIT_SET(size, lastnum, mask);
                                state = NONE;
                                break;
                        case NUM:
@@ -80,7 +94,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
                        case NONE:
                                break;
                        case NUM:
-                               CPU_SET(curnum, mask);
+                               BIT_SET(size, curnum, mask);
                                state = NONE;
                                break;
                        case DASH:
@@ -102,7 +116,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
                case NONE:
                        break;
                case NUM:
-                       CPU_SET(curnum, mask);
+                       BIT_SET(size, curnum, mask);
                        break;
                case DASH:
                        goto parserr;
@@ -111,3 +125,63 @@ cpuset_parselist(const char *list, cpuset_t *mask)
 parserr:
        return (CPUSET_PARSE_ERROR);
 }
+
+/*
+ * permissively parse policy:domain list
+ * allow:
+ *     round-robin:0-4         explicit
+ *     round-robin:all         explicit root domains
+ *     0-4                     implicit root policy
+ *     round-robin             implicit root domains
+ *     all                     explicit root domains and implicit policy
+ */
+int
+domainset_parselist(const char *list, domainset_t *mask, int *policyp)
+{
+       domainset_t rootmask;
+       const struct numa_policy *policy;
+       const char *l;
+       int p;
+
+       /*
+        * Use the rootset's policy as the default for unspecified policies.
+        */
+       if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+           sizeof(rootmask), &rootmask, &p) != 0)
+               return (CPUSET_PARSE_GETDOMAIN);
+
+       if (list == NULL || strcasecmp(list, "all") == 0 || *list == '\0') {
+               *policyp = p;
+               DOMAINSET_COPY(&rootmask, mask);
+               return (CPUSET_PARSE_OK);
+       }
+
+       l = list;
+       for (policy = &policies[0]; policy->name != NULL; policy++) {
+               if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
+                       p = policy->policy;
+                       l += strlen(policy->name);
+                       if (*l != ':' && *l != '\0')
+                               return (CPUSET_PARSE_ERROR);
+                       if (*l == ':')
+                               l++;
+                       break;
+               }
+       }
+       *policyp = p;
+
+       return (parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE));
+}
+
+int
+cpuset_parselist(const char *list, cpuset_t *mask)
+{
+       if (strcasecmp(list, "all") == 0) {
+               if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+                   sizeof(*mask), mask) != 0)
+                       return (CPUSET_PARSE_GETAFFINITY);
+               return (CPUSET_PARSE_OK);
+       }
+
+       return (parselist(list, (struct bitset *)mask, CPU_SETSIZE));
+}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index 919855184caf..7d8bfdf67fac 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -213,7 +213,13 @@ int        cpuset_parselist(const char *list, cpuset_t 
*mask);
 #define CPUSET_PARSE_OK                        0
 #define CPUSET_PARSE_GETAFFINITY       -1
 #define CPUSET_PARSE_ERROR             -2
-#define CPUSET_PARSE_INVALID_CPU       -3
+#define CPUSET_PARSE_OUT_OF_RANGE      -3
+#define CPUSET_PARSE_GETDOMAIN         -4
+#define CPUSET_PARSE_INVALID_CPU       CPUSET_PARSE_OUT_OF_RANGE /* backwards 
compat */
+#endif
+
+#ifdef _SYS_DOMAINSET_H_
+int    domainset_parselist(const char *list, domainset_t *mask, int *policyp);
 #endif
 
 __END_DECLS

Reply via email to