diff options
-rw-r--r-- | coreutils/nproc.c | 9 | ||||
-rw-r--r-- | include/libbb.h | 7 | ||||
-rw-r--r-- | libbb/Kbuild.src | 1 | ||||
-rw-r--r-- | libbb/popcnt.c | 46 | ||||
-rw-r--r-- | networking/ifupdown.c | 8 | ||||
-rw-r--r-- | networking/ipcalc.c | 21 | ||||
-rw-r--r-- | networking/libiproute/utils.c | 11 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 15 |
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; | |||
397 | uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; | 397 | uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; |
398 | #endif | 398 | #endif |
399 | 399 | ||
400 | unsigned FAST_FUNC bb_popcnt_32(uint32_t m); | ||
401 | #if ULONG_MAX > 0xffffffff | ||
402 | unsigned FAST_FUNC bb_popcnt_long(unsigned_long m); | ||
403 | #else | ||
404 | #define bb_popcnt_long(m) bb_popcnt_32(m) | ||
405 | #endif | ||
406 | |||
400 | unsigned long FAST_FUNC isqrt(unsigned long long N); | 407 | unsigned long FAST_FUNC isqrt(unsigned long long N); |
401 | 408 | ||
402 | unsigned long long monotonic_ns(void) FAST_FUNC; | 409 | unsigned 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 | |||
72 | lib-y += perror_nomsg_and_die.o | 72 | lib-y += perror_nomsg_and_die.o |
73 | lib-y += pidfile.o | 73 | lib-y += pidfile.o |
74 | lib-y += platform.o | 74 | lib-y += platform.o |
75 | lib-y += popcnt.o | ||
75 | lib-y += printable.o | 76 | lib-y += printable.o |
76 | lib-y += printable_string.o | 77 | lib-y += printable_string.o |
77 | lib-y += print_flags.o | 78 | lib-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 | |||
11 | unsigned 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 | ||
37 | unsigned 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 | ||
75 | static 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 | ||
89 | int 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 */ | ||
154 | static 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; |