X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Futil.c;h=c2ffab247ff3e7b8c4914c1c0f5e36a9b44f0198;hb=ac60863f78e412004c5b69f5a64a49bc6f0bc46d;hp=76c33cd7cee0df99f87123ddd4194f400b40d97b;hpb=bd3ad2c3508aaf7283f3ee041ecd3e5108471b21;p=sliver-openvswitch.git diff --git a/lib/util.c b/lib/util.c index 76c33cd7c..c2ffab247 100644 --- a/lib/util.c +++ b/lib/util.c @@ -16,6 +16,7 @@ #include #include "util.h" +#include #include #include #include @@ -26,10 +27,14 @@ #include #include #include +#include "bitmap.h" #include "byte-order.h" #include "coverage.h" #include "ovs-thread.h" #include "vlog.h" +#ifdef HAVE_PTHREAD_SET_NAME_NP +#include +#endif VLOG_DEFINE_THIS_MODULE(util); @@ -396,19 +401,32 @@ get_subprogram_name(void) return name ? name : ""; } -/* Sets 'name' as the name of the currently running thread or process. (This - * appears in log messages and may also be visible in system process listings - * and debuggers.) */ +/* Sets the formatted value of 'format' as the name of the currently running + * thread or process. (This appears in log messages and may also be visible in + * system process listings and debuggers.) */ void -set_subprogram_name(const char *name) +set_subprogram_name(const char *format, ...) { - free(subprogram_name_set(xstrdup(name))); + char *pname; + + if (format) { + va_list args; + + va_start(args, format); + pname = xvasprintf(format, args); + va_end(args); + } else { + pname = xstrdup(program_name); + } + + free(subprogram_name_set(pname)); + #if HAVE_GLIBC_PTHREAD_SETNAME_NP - pthread_setname_np(pthread_self(), name); + pthread_setname_np(pthread_self(), pname); #elif HAVE_NETBSD_PTHREAD_SETNAME_NP - pthread_setname_np(pthread_self(), "%s", name); + pthread_setname_np(pthread_self(), "%s", pname); #elif HAVE_PTHREAD_SET_NAME_NP - pthread_set_name_np(pthread_self(), name); + pthread_set_name_np(pthread_self(), pname); #endif } @@ -871,16 +889,14 @@ log_2_ceil(uint32_t n) } /* Returns the number of trailing 0-bits in 'n'. Undefined if 'n' == 0. */ -#if !defined(UINT_MAX) || !defined(UINT32_MAX) -#error "Someone screwed up the #includes." -#elif __GNUC__ >= 4 && UINT_MAX == UINT32_MAX +#if __GNUC__ >= 4 /* Defined inline in util.h. */ #else -static int -raw_ctz(uint32_t n) +int +raw_ctz(uint64_t n) { - unsigned int k; - int count = 31; + uint64_t k; + int count = 63; #define CTZ_STEP(X) \ k = n << (X); \ @@ -888,6 +904,7 @@ raw_ctz(uint32_t n) count -= X; \ n = k; \ } + CTZ_STEP(32); CTZ_STEP(16); CTZ_STEP(8); CTZ_STEP(4); @@ -900,8 +917,8 @@ raw_ctz(uint32_t n) #endif /* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */ -unsigned int -popcount(uint32_t x) +static unsigned int +count_1bits_32(uint32_t x) { /* In my testing, this implementation is over twice as fast as any other * portable implementation that I tried, including GCC 4.4 @@ -923,14 +940,21 @@ popcount(uint32_t x) #define INIT32(X) INIT16(X), INIT16((X) + 16) #define INIT64(X) INIT32(X), INIT32((X) + 32) - static const uint8_t popcount8[256] = { + static const uint8_t count_1bits_8[256] = { INIT64(0), INIT64(64), INIT64(128), INIT64(192) }; - return (popcount8[x & 0xff] + - popcount8[(x >> 8) & 0xff] + - popcount8[(x >> 16) & 0xff] + - popcount8[x >> 24]); + return (count_1bits_8[x & 0xff] + + count_1bits_8[(x >> 8) & 0xff] + + count_1bits_8[(x >> 16) & 0xff] + + count_1bits_8[x >> 24]); +} + +/* Returns the number of 1-bits in 'x', between 0 and 64 inclusive. */ +unsigned int +count_1bits(uint64_t x) +{ + return count_1bits_32(x) + count_1bits_32(x >> 32); } /* Returns true if the 'n' bytes starting at 'p' are zeros. */ @@ -1229,3 +1253,444 @@ bitwise_get(const void *src, unsigned int src_len, n_bits); return ntohll(value); } + +/* ovs_scan */ + +struct scan_spec { + unsigned int width; + enum { + SCAN_DISCARD, + SCAN_CHAR, + SCAN_SHORT, + SCAN_INT, + SCAN_LONG, + SCAN_LLONG, + SCAN_INTMAX_T, + SCAN_PTRDIFF_T, + SCAN_SIZE_T + } type; +}; + +static const char * +skip_spaces(const char *s) +{ + while (isspace((unsigned char) *s)) { + s++; + } + return s; +} + +static const char * +scan_int(const char *s, const struct scan_spec *spec, int base, va_list *args) +{ + const char *start = s; + uintmax_t value; + bool negative; + int n_digits; + + negative = *s == '-'; + s += *s == '-' || *s == '+'; + + if ((!base || base == 16) && *s == '0' && (s[1] == 'x' || s[1] == 'X')) { + base = 16; + s += 2; + } else if (!base) { + base = *s == '0' ? 8 : 10; + } + + if (s - start >= spec->width) { + return NULL; + } + + value = 0; + n_digits = 0; + while (s - start < spec->width) { + int digit = hexit_value(*s); + + if (digit < 0 || digit >= base) { + break; + } + value = value * base + digit; + n_digits++; + s++; + } + if (!n_digits) { + return NULL; + } + + if (negative) { + value = -value; + } + + switch (spec->type) { + case SCAN_DISCARD: + break; + case SCAN_CHAR: + *va_arg(*args, char *) = value; + break; + case SCAN_SHORT: + *va_arg(*args, short int *) = value; + break; + case SCAN_INT: + *va_arg(*args, int *) = value; + break; + case SCAN_LONG: + *va_arg(*args, long int *) = value; + break; + case SCAN_LLONG: + *va_arg(*args, long long int *) = value; + break; + case SCAN_INTMAX_T: + *va_arg(*args, intmax_t *) = value; + break; + case SCAN_PTRDIFF_T: + *va_arg(*args, ptrdiff_t *) = value; + break; + case SCAN_SIZE_T: + *va_arg(*args, size_t *) = value; + break; + } + return s; +} + +static const char * +skip_digits(const char *s) +{ + while (*s >= '0' && *s <= '9') { + s++; + } + return s; +} + +static const char * +scan_float(const char *s, const struct scan_spec *spec, va_list *args) +{ + const char *start = s; + long double value; + char *tail; + char *copy; + bool ok; + + s += *s == '+' || *s == '-'; + s = skip_digits(s); + if (*s == '.') { + s = skip_digits(s + 1); + } + if (*s == 'e' || *s == 'E') { + s++; + s += *s == '+' || *s == '-'; + s = skip_digits(s); + } + + if (s - start > spec->width) { + s = start + spec->width; + } + + copy = xmemdup0(start, s - start); + value = strtold(copy, &tail); + ok = *tail == '\0'; + free(copy); + if (!ok) { + return NULL; + } + + switch (spec->type) { + case SCAN_DISCARD: + break; + case SCAN_INT: + *va_arg(*args, float *) = value; + break; + case SCAN_LONG: + *va_arg(*args, double *) = value; + break; + case SCAN_LLONG: + *va_arg(*args, long double *) = value; + break; + + case SCAN_CHAR: + case SCAN_SHORT: + case SCAN_INTMAX_T: + case SCAN_PTRDIFF_T: + case SCAN_SIZE_T: + NOT_REACHED(); + } + return s; +} + +static void +scan_output_string(const struct scan_spec *spec, + const char *s, size_t n, + va_list *args) +{ + if (spec->type != SCAN_DISCARD) { + char *out = va_arg(*args, char *); + memcpy(out, s, n); + out[n] = '\0'; + } +} + +static const char * +scan_string(const char *s, const struct scan_spec *spec, va_list *args) +{ + size_t n; + + for (n = 0; n < spec->width; n++) { + if (!s[n] || isspace((unsigned char) s[n])) { + break; + } + } + if (!n) { + return NULL; + } + + scan_output_string(spec, s, n, args); + return s + n; +} + +static const char * +parse_scanset(const char *p_, unsigned long *set, bool *complemented) +{ + const uint8_t *p = (const uint8_t *) p_; + + *complemented = *p == '^'; + p += *complemented; + + if (*p == ']') { + bitmap_set1(set, ']'); + p++; + } + + while (*p && *p != ']') { + if (p[1] == '-' && p[2] != ']' && p[2] > *p) { + bitmap_set_multiple(set, *p, p[2] - *p + 1, true); + p += 3; + } else { + bitmap_set1(set, *p++); + } + } + if (*p == ']') { + p++; + } + return (const char *) p; +} + +static const char * +scan_set(const char *s, const struct scan_spec *spec, const char **pp, + va_list *args) +{ + unsigned long set[BITMAP_N_LONGS(UCHAR_MAX + 1)]; + bool complemented; + unsigned int n; + + /* Parse the scan set. */ + memset(set, 0, sizeof set); + *pp = parse_scanset(*pp, set, &complemented); + + /* Parse the data. */ + n = 0; + while (s[n] + && bitmap_is_set(set, (unsigned char) s[n]) == !complemented + && n < spec->width) { + n++; + } + if (!n) { + return NULL; + } + scan_output_string(spec, s, n, args); + return s + n; +} + +static const char * +scan_chars(const char *s, const struct scan_spec *spec, va_list *args) +{ + unsigned int n = spec->width == UINT_MAX ? 1 : spec->width; + + if (strlen(s) < n) { + return NULL; + } + if (spec->type != SCAN_DISCARD) { + memcpy(va_arg(*args, char *), s, n); + } + return s + n; +} + +/* This is an implementation of the standard sscanf() function, with the + * following exceptions: + * + * - It returns true if the entire template was successfully scanned and + * converted, false if any conversion failed. + * + * - The standard doesn't define sscanf() behavior when an out-of-range value + * is scanned, e.g. if a "%"PRIi8 conversion scans "-1" or "0x1ff". Some + * implementations consider this an error and stop scanning. This + * implementation never considers an out-of-range value an error; instead, + * it stores the least-significant bits of the converted value in the + * destination, e.g. the value 255 for both examples earlier. + * + * - Only single-byte characters are supported, that is, the 'l' modifier + * on %s, %[, and %c is not supported. The GNU extension 'a' modifier is + * also not supported. + * + * - %p is not supported. + */ +bool +ovs_scan(const char *s, const char *template, ...) +{ + const char *const start = s; + bool ok = false; + const char *p; + va_list args; + + va_start(args, template); + p = template; + while (*p != '\0') { + struct scan_spec spec; + unsigned char c = *p++; + bool discard; + + if (isspace(c)) { + s = skip_spaces(s); + continue; + } else if (c != '%') { + if (*s != c) { + goto exit; + } + s++; + continue; + } else if (*p == '%') { + if (*s++ != '%') { + goto exit; + } + p++; + continue; + } + + /* Parse '*' flag. */ + discard = *p == '*'; + p += discard; + + /* Parse field width. */ + spec.width = 0; + while (*p >= '0' && *p <= '9') { + spec.width = spec.width * 10 + (*p++ - '0'); + } + if (spec.width == 0) { + spec.width = UINT_MAX; + } + + /* Parse type modifier. */ + switch (*p) { + case 'h': + if (p[1] == 'h') { + spec.type = SCAN_CHAR; + p += 2; + } else { + spec.type = SCAN_SHORT; + p++; + } + break; + + case 'j': + spec.type = SCAN_INTMAX_T; + p++; + break; + + case 'l': + if (p[1] == 'l') { + spec.type = SCAN_LLONG; + p += 2; + } else { + spec.type = SCAN_LONG; + p++; + } + break; + + case 'L': + case 'q': + spec.type = SCAN_LLONG; + p++; + break; + + case 't': + spec.type = SCAN_PTRDIFF_T; + p++; + break; + + case 'z': + spec.type = SCAN_SIZE_T; + p++; + break; + + default: + spec.type = SCAN_INT; + break; + } + + if (discard) { + spec.type = SCAN_DISCARD; + } + + c = *p++; + if (c != 'c' && c != 'n' && c != '[') { + s = skip_spaces(s); + } + switch (c) { + case 'd': + s = scan_int(s, &spec, 10, &args); + break; + + case 'i': + s = scan_int(s, &spec, 0, &args); + break; + + case 'o': + s = scan_int(s, &spec, 8, &args); + break; + + case 'u': + s = scan_int(s, &spec, 10, &args); + break; + + case 'x': + case 'X': + s = scan_int(s, &spec, 16, &args); + break; + + case 'e': + case 'f': + case 'g': + case 'E': + case 'G': + s = scan_float(s, &spec, &args); + break; + + case 's': + s = scan_string(s, &spec, &args); + break; + + case '[': + s = scan_set(s, &spec, &p, &args); + break; + + case 'c': + s = scan_chars(s, &spec, &args); + break; + + case 'n': + if (spec.type != SCAN_DISCARD) { + *va_arg(args, int *) = s - start; + } + break; + } + + if (!s) { + goto exit; + } + } + ok = true; + +exit: + va_end(args); + return ok; +} +