aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coreutils/nproc.c9
-rw-r--r--include/libbb.h7
-rw-r--r--libbb/Kbuild.src1
-rw-r--r--libbb/popcnt.c46
-rw-r--r--networking/ifupdown.c8
-rw-r--r--networking/ipcalc.c21
-rw-r--r--networking/libiproute/utils.c11
-rw-r--r--networking/udhcp/dhcpc.c15
8 files changed, 66 insertions, 52 deletions
diff --git a/coreutils/nproc.c b/coreutils/nproc.c
index a0d818c59..df63bf57a 100644
--- a/coreutils/nproc.c
+++ b/coreutils/nproc.c
@@ -56,13 +56,10 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
56 unsigned long *mask = get_malloc_cpu_affinity(0, &sz); 56 unsigned long *mask = get_malloc_cpu_affinity(0, &sz);
57 sz /= sizeof(long); 57 sz /= sizeof(long);
58 for (i = 0; i < sz; i++) { 58 for (i = 0; i < sz; i++) {
59 unsigned long m = mask[i]; 59 if (mask[i] != 0) /* most mask[i] are usually 0 */
60 while (m) { 60 count += bb_popcnt_long(mask[i]);
61 if (m & 1)
62 count++;
63 m >>= 1;
64 }
65 } 61 }
62 IF_FEATURE_CLEAN_UP(free(mask);)
66 } 63 }
67 64
68 IF_LONG_OPTS(count -= ignore;) 65 IF_LONG_OPTS(count -= ignore;)
diff --git a/include/libbb.h b/include/libbb.h
index 67d29f843..6914b5882 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -397,6 +397,13 @@ extern int *BB_GLOBAL_CONST bb_errno;
397uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; 397uint64_t bb_bswap_64(uint64_t x) FAST_FUNC;
398#endif 398#endif
399 399
400unsigned FAST_FUNC bb_popcnt_32(uint32_t m);
401#if ULONG_MAX > 0xffffffff
402unsigned FAST_FUNC bb_popcnt_long(unsigned_long m);
403#else
404#define bb_popcnt_long(m) bb_popcnt_32(m)
405#endif
406
400unsigned long FAST_FUNC isqrt(unsigned long long N); 407unsigned long FAST_FUNC isqrt(unsigned long long N);
401 408
402unsigned long long monotonic_ns(void) FAST_FUNC; 409unsigned long long monotonic_ns(void) FAST_FUNC;
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index a0e2a6da7..cb8d2c2ec 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -72,6 +72,7 @@ lib-y += perror_nomsg.o
72lib-y += perror_nomsg_and_die.o 72lib-y += perror_nomsg_and_die.o
73lib-y += pidfile.o 73lib-y += pidfile.o
74lib-y += platform.o 74lib-y += platform.o
75lib-y += popcnt.o
75lib-y += printable.o 76lib-y += printable.o
76lib-y += printable_string.o 77lib-y += printable_string.o
77lib-y += print_flags.o 78lib-y += print_flags.o
diff --git a/libbb/popcnt.c b/libbb/popcnt.c
new file mode 100644
index 000000000..fe8cd240f
--- /dev/null
+++ b/libbb/popcnt.c
@@ -0,0 +1,46 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2024 Denys Vlasenko
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9#include "libbb.h"
10
11unsigned FAST_FUNC bb_popcnt_32(uint32_t m)
12{
13 /* replace each 2 bit group with the count of set bits in it */
14 /* 00->00 01->01 10->01 11->10 */
15 m = m - ((m >> 1) & 0x55555555);
16 /* in each 4 bit group, add two 2-bit counts */
17 m = (m & 0x33333333) + ((m >> 2) & 0x33333333);
18 /* in each 8 bit group, add two 4-bit counts (in fact, 3-bit, 0nnn with n=0..4) */
19 m = (m + (m >> 4)) & 0x0f0f0f0f;
20#if 1 /* assume 32*32->32 multiply is fast */
21 m = m * 0x01010101; /* top byte = m + (m<<8) + (m<<16) + (m<<24) */
22 return m >> 24;
23#else
24 /* 0000aaaa0000bbbb0000cccc0000dddd */
25 /* + 0000aaaa0000bbbb0000cccc */
26 /* = 0000xxxx000_a+b_000xxxxx000_c+d_ (we don't care about x bits) */
27 m += m >> 8; /* in each 16-bit group, lowest 5 bits is the count */
28 /* 0000xxxx000_a+b_000xxxxx000_c+d_ */
29 /* + 0000xxxx000_a+b_ */
30 /* = 0000xxxx000xxxxx00xxxxxx00a+b+cd */
31 m += m >> 16; /* in each 32-bit group, lowest 6 bits is the count */
32 return m & 0x3f; /* clear x bits */
33#endif
34}
35
36#if ULONG_MAX > 0xffffffff
37unsigned FAST_FUNC bb_popcnt_long(unsigned long m)
38{
39 BUILD_BUG_ON(sizeof(m) != 8);
40 /* 64-bit version of bb_popcnt_32 exists, but it uses 64-bit constants,
41 * which are awkward to generate on assembly level on most CPUs.
42 * For now, just add two 32-bit counts:
43 */
44 return bb_popcnt_32((uint32_t)m) + bb_popcnt_32((uint32_t)(m >> 32));
45}
46#endif
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 6c4ae27f2..9c3640be7 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -306,7 +306,6 @@ static int count_netmask_bits(const char *dotted_quad)
306// d = ~d; /* 11110000 -> 00001111 */ 306// d = ~d; /* 11110000 -> 00001111 */
307 307
308 /* Shorter version */ 308 /* Shorter version */
309 int result;
310 struct in_addr ip; 309 struct in_addr ip;
311 unsigned d; 310 unsigned d;
312 311
@@ -316,12 +315,7 @@ static int count_netmask_bits(const char *dotted_quad)
316 d = ~d; /* 11110000 -> 00001111 */ 315 d = ~d; /* 11110000 -> 00001111 */
317 if (d & (d+1)) /* check that it is in 00001111 form */ 316 if (d & (d+1)) /* check that it is in 00001111 form */
318 return -1; /* no it is not */ 317 return -1; /* no it is not */
319 result = 32; 318 return bb_popcnt_32(~d);
320 while (d) {
321 d >>= 1;
322 result--;
323 }
324 return result;
325} 319}
326# endif 320# endif
327 321
diff --git a/networking/ipcalc.c b/networking/ipcalc.c
index 92e7b289d..3ec473c6b 100644
--- a/networking/ipcalc.c
+++ b/networking/ipcalc.c
@@ -71,25 +71,6 @@ static unsigned long get_netmask(unsigned long ipaddr)
71 return 0; 71 return 0;
72} 72}
73 73
74#if ENABLE_FEATURE_IPCALC_FANCY
75static int get_prefix(unsigned long netmask)
76{
77 unsigned long msk = 0x80000000;
78 int ret = 0;
79
80 netmask = htonl(netmask);
81 while (msk) {
82 if (netmask & msk)
83 ret++;
84 msk >>= 1;
85 }
86 return ret;
87}
88#else
89int get_prefix(unsigned long netmask);
90#endif
91
92
93#define NETMASK 0x01 74#define NETMASK 0x01
94#define BROADCAST 0x02 75#define BROADCAST 0x02
95#define NETWORK 0x04 76#define NETWORK 0x04
@@ -210,7 +191,7 @@ int ipcalc_main(int argc UNUSED_PARAM, char **argv)
210 191
211 if (ENABLE_FEATURE_IPCALC_FANCY) { 192 if (ENABLE_FEATURE_IPCALC_FANCY) {
212 if (opt & NETPREFIX) { 193 if (opt & NETPREFIX) {
213 printf("PREFIX=%i\n", get_prefix(netmask)); 194 printf("PREFIX=%i\n", bb_popcnt_32(netmask));
214 } 195 }
215 196
216 if (opt & HOSTNAME) { 197 if (opt & HOSTNAME) {
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c
index 4ce230356..3cce4a06e 100644
--- a/networking/libiproute/utils.c
+++ b/networking/libiproute/utils.c
@@ -175,14 +175,13 @@ static void get_prefix_1(inet_prefix *dst, char *arg, int family)
175 if (netmask_pfx.family == AF_INET) { 175 if (netmask_pfx.family == AF_INET) {
176 /* fill in prefix length of dotted quad */ 176 /* fill in prefix length of dotted quad */
177 uint32_t mask = ntohl(netmask_pfx.data[0]); 177 uint32_t mask = ntohl(netmask_pfx.data[0]);
178 uint32_t host = ~mask; 178 uint32_t inv = ~mask;
179 179
180 /* a valid netmask must be 2^n - 1 */ 180 /* a valid netmask must be 11..10..00 */
181 if (host & (host + 1)) 181 if (inv & (inv + 1))
182 goto bad; 182 goto bad; /* inv is not 00..01..11 */
183 183
184 for (plen = 0; mask; mask <<= 1) 184 plen = bb_popcnt_32(mask);
185 ++plen;
186 if (plen > dst->bitlen) 185 if (plen > dst->bitlen)
187 goto bad; 186 goto bad;
188 /* dst->flags |= PREFIXLEN_SPECIFIED; */ 187 /* dst->flags |= PREFIXLEN_SPECIFIED; */
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 07e2eadfe..e44086c2e 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -150,18 +150,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
150 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); 150 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
151} 151}
152 152
153/* really simple implementation, just count the bits */
154static int mton(uint32_t mask)
155{
156 int i = 0;
157 mask = ntohl(mask); /* 111110000-like bit pattern */
158 while (mask) {
159 i++;
160 mask <<= 1;
161 }
162 return i;
163}
164
165#if ENABLE_FEATURE_UDHCPC_SANITIZEOPT 153#if ENABLE_FEATURE_UDHCPC_SANITIZEOPT
166/* Check if a given name represents a valid DNS name */ 154/* Check if a given name represents a valid DNS name */
167/* See RFC1035, 2.3.1 */ 155/* See RFC1035, 2.3.1 */
@@ -508,7 +496,8 @@ static void fill_envp(struct dhcp_packet *packet)
508 /* Generate extra envvar for DHCP_SUBNET, $mask */ 496 /* Generate extra envvar for DHCP_SUBNET, $mask */
509 uint32_t subnet; 497 uint32_t subnet;
510 move_from_unaligned32(subnet, opt_item->data); 498 move_from_unaligned32(subnet, opt_item->data);
511 putenvp(xasprintf("mask=%u", mton(subnet))); 499//FIXME: we do not check that subnet has bit pattern 11..10..0
500 putenvp(xasprintf("mask=%u", bb_popcnt_32(subnet)));
512 } 501 }
513 } else { 502 } else {
514 unsigned ofs; 503 unsigned ofs;