mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] [PATCH v3] sysconf: add _SC_NPROCESSORS_CONF support
@ 2021-07-06  9:55 Vincent Donnefort
  0 siblings, 0 replies; 12+ messages in thread
From: Vincent Donnefort @ 2021-07-06  9:55 UTC (permalink / raw)
  To: musl; +Cc: jyknight, Vincent Donnefort

Currently, _SC_NPROCESSORS_CONF is always equal to _SC_NPROCESSORS_ONLN.
However, it is expected from the first one to give the total number of
CPUs that the system can contain, while the later must return only the
number of CPUs which are currently online. This distinction is important
for a software such as trace-cmd. Trace-cmd is a front-end for the kernel
tracing tool ftrace. When recording traces, trace-cmd needs to get the
otal number of CPUs available in the system (_SC_NPROCESSORS_CONF) and not
only the online ones otherwise if a CPU goes offline some data might be
missing.

Hence, add a specific method to get _SC_NPROCESSORS_CONF, based on the
sysfs file /sys/devices/system/cpu/possible. This static file will not
change during the lifespan of the Linux kernel and contains a CPU mask
with all the CPUs that can be brought online.

diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c
index 3baaed32..b4b842f5 100644
--- a/src/conf/sysconf.c
+++ b/src/conf/sysconf.c
@@ -1,8 +1,10 @@
+#include <ctype.h>
 #include <unistd.h>
 #include <limits.h>
 #include <errno.h>
 #include <sys/resource.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <sys/sysinfo.h>
 #include "syscall.h"
 #include "libc.h"
@@ -22,6 +24,73 @@
 
 #define RLIM(x) (-32768|(RLIMIT_ ## x))
 
+#define POSSIBLE_MAX_READ 128
+#define char_to_int(prev, num) (10 * prev + (num - '0'))
+
+static inline int get_nrprocessors_conf(void)
+{
+	FILE *f;
+	char buffer[POSSIBLE_MAX_READ];
+	int start_chunk = 0, end_chunk = -1;
+	unsigned int cnt = 0, i = 0;
+	size_t ret;
+
+	f = fopen("/sys/devices/system/cpu/possible", "r");
+	if (!f)
+		return 0;
+
+	ret = fread(buffer, sizeof(*buffer),
+		    sizeof(buffer) / sizeof(*buffer), f);
+	if (!feof(f) || ferror(f) || ret < 2)
+		goto end;
+
+	/*
+	 * Count the number of CPUs in the CPU mask. A CPU Mask is described by
+	 * chunks. Chunks have the following format: "<start>-<end>" and are
+	 * separated by ",". A chunk can be composed of a single CPU.
+	 *
+	 * e.g. "0-1,4" -> 3 CPUs
+	 */
+        while (i < POSSIBLE_MAX_READ) {
+                if (buffer[i] == ',' || buffer[i] == '\0') {
+			if (end_chunk > -1)
+				cnt += (end_chunk - start_chunk) + 1;
+			else
+				cnt++;
+                        start_chunk = 0;
+			end_chunk = -1;
+			if (buffer[i] == '\0')
+				break;
+                } else if (buffer[i] == '-') {
+			end_chunk = 0;
+                } else if (isdigit(buffer[i])) {
+                        if (end_chunk == -1)
+                                start_chunk =
+					char_to_int(start_chunk, buffer[i]);
+                        else
+                                end_chunk = char_to_int(end_chunk, buffer[i]);
+                }
+                i++;
+        }
+
+end:
+	fclose(f);
+
+	return cnt;
+}
+
+static inline int get_nrprocessors_onln(void)
+{
+	unsigned char set[128] = {1};
+	int i, cnt;
+
+	__syscall(SYS_sched_getaffinity, 0, sizeof set, set);
+	for (i=cnt=0; i<sizeof set; i++)
+		for (; set[i]; set[i]&=set[i]-1, cnt++);
+
+	return cnt;
+}
+
 long sysconf(int name)
 {
 	static const short values[] = {
@@ -193,14 +262,13 @@ long sysconf(int name)
 		return SEM_VALUE_MAX;
 	case JT_DELAYTIMER_MAX & 255:
 		return DELAYTIMER_MAX;
-	case JT_NPROCESSORS_CONF & 255:
+	case JT_NPROCESSORS_CONF & 255: ;
+		int cnt = get_nrprocessors_conf();
+		if (cnt > 0)
+			return cnt;
+		return get_nrprocessors_onln();
 	case JT_NPROCESSORS_ONLN & 255: ;
-		unsigned char set[128] = {1};
-		int i, cnt;
-		__syscall(SYS_sched_getaffinity, 0, sizeof set, set);
-		for (i=cnt=0; i<sizeof set; i++)
-			for (; set[i]; set[i]&=set[i]-1, cnt++);
-		return cnt;
+		return get_nrprocessors_onln();
 	case JT_PHYS_PAGES & 255:
 	case JT_AVPHYS_PAGES & 255: ;
 		unsigned long long mem;
-- 
2.27.0


^ permalink raw reply	[flat|nested] 12+ messages in thread
* Re: [musl] [PATCH v3] sysconf: add _SC_NPROCESSORS_CONF support
@ 2021-07-10  5:31 jason
  2021-07-10 17:11 ` Rich Felker
  2021-07-10 17:29 ` Samuel Holland
  0 siblings, 2 replies; 12+ messages in thread
From: jason @ 2021-07-10  5:31 UTC (permalink / raw)
  To: musl, vincent.donnefort; +Cc: jason

Here's a simpler bit of code to do the same thing.  The differences:
- Doesn't bother using stdio.  /proc and /sys reads like this don't sleep
  and so don't return short or EINTR or any of that hair.

- Check for the terminating newline, and use it in the parsing loop
  to trigger completing a range, just like ','.

  The previous code never actually ensured that the buffer was '\0'
  terminated. :-(

- Use one "current number being parsed" variable rather than two.
  Just copy n to prev_n on finding a '-'.  (Feel free to bikeshed the
  variable names to "range_start" or something if you prefer.)

If you do want to use a FILE *, musl should probably have an internal
API for reading into the stdio buffer and parsing straight from there,
avoiding the separate stack buffer.  (Or even allocating the FILE on
the stack and avoiding the malloc.)

This is probably far from the last small config file (/proc or /sys or
perhaps something like /etc/hostname) that someone will want to access.

(You could even get ambitious and make it reallocate the buffer as
required to get the whole file into memory  Probably something other
code would be interested in, like timezone parsing.)


#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

long get_nrprocessors_conf1(void)
{
	int fd = open("/sys/devices/system/cpu/possible",
			O_RDONLY | O_NOCTTY | O_CLOEXEC);
	if (fd < 0)
		goto failure;

	char buffer[128];	/* Some reasonable size. */
	ssize_t ss = read(fd, buffer, sizeof buffer);
	/*
	 * Short reads, EINTR, etc. can't happen with /sys files.
	 * We could in theory preserve the read's errno in case the close
	 * overwrites it, but that seems excessive.
	 */
	if (close(fd) < 0 || ss < 0)
		goto failure;
	if (ss < 2 || buffer[ss-1] != '\n')
		goto parse_error;
	/*
	 * The possible CPUs are given as a comma-separated list of ranges,
	 * with each range being either a single decimal integer ("1") or
	 * a hyphen-separated range ("1-10").
	 *
	 * Q: How careful do we want the parsing to be?  For now, assume
	 * the kernel can be trusted not to give us "1-2-3" or ",," or
	 * other strangeness.
	 */
	char const *p = buffer;
	unsigned prev_n = -1u;
	unsigned n = 0;
	unsigned total = 0;
	for (;;) {
		char c = *p++;
		switch (c) {
		  case '0': case '1': case '2': case '3': case '4':
		  case '5': case '6': case '7': case '8': case '9':
			if (n > (-1u - 9)/10)
				goto parse_error;
			n = 10 * n + c - '0';
			break;
		  case '-':
			prev_n = n;
			n = 0;
			break;
		  case ',': case '\n':
			if (n > prev_n)
				total += n - prev_n;
			total++;
			if (c == '\n')
				return (long)total;	/* Success! */
			prev_n = -1u;
			n = 0;
			break;
		  default:
			goto parse_error;
		}
	}

parse_error:
	errno = ENOTSUP;	/* What's a good error to return? */
failure:
	return -1;
}

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-08-07 16:31 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-06  9:55 [musl] [PATCH v3] sysconf: add _SC_NPROCESSORS_CONF support Vincent Donnefort
2021-07-10  5:31 jason
2021-07-10 17:11 ` Rich Felker
2021-07-10 17:29 ` Samuel Holland
2021-07-10 19:44   ` Rich Felker
2021-07-12 13:08     ` Vincent Donnefort
2021-07-12 15:41       ` Rich Felker
2021-07-12 16:32         ` Vincent Donnefort
2021-07-12 17:14           ` Rich Felker
2021-07-12 18:12             ` Vincent Donnefort
2021-08-07 14:52             ` James Y Knight
2021-08-07 16:29           ` Leah Neukirchen

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).