#include <config.h>
#include "util.h"
+#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
+#include "bitmap.h"
#include "byte-order.h"
#include "coverage.h"
#include "ovs-thread.h"
#include "vlog.h"
+#ifdef HAVE_PTHREAD_SET_NAME_NP
+#include <pthread_np.h>
+#endif
VLOG_DEFINE_THIS_MODULE(util);
/* argv[0] without directory names. */
const char *program_name;
-/* Ordinarily "" but set to "monitor" for a monitor process or "worker" for a
- * worker process. */
-const char *subprogram_name = "";
+/* Name for the currently running thread or process, for log messages, process
+ * listings, and debuggers. */
+DEFINE_PER_THREAD_MALLOCED_DATA(char *, subprogram_name);
/* --version option output. */
static char *program_version;
/* Buffer used by ovs_strerror(). */
-DEFINE_PER_THREAD_DATA(struct { char s[128]; }, strerror_buffer, { "" });
+DEFINE_STATIC_PER_THREAD_DATA(struct { char s[128]; },
+ strerror_buffer,
+ { "" });
void
ovs_assert_failure(const char *where, const char *function,
void
ovs_error_valist(int err_no, const char *format, va_list args)
{
+ const char *subprogram_name = get_subprogram_name();
int save_errno = errno;
if (subprogram_name[0]) {
* is too short). We don't check the actual failure reason because
* POSIX requires strerror_r() to return the error but old glibc
* (before 2.13) returns -1 and sets errno. */
- snprintf(buffer, BUFSIZE, "Unknown error %d", error);
+ snprintf(buffer, BUFSIZE, "Unknown error %"PRIuSIZE, error);
}
#endif
}
}
+/* Returns the name of the currently running thread or process. */
+const char *
+get_subprogram_name(void)
+{
+ const char *name = subprogram_name_get();
+ return name ? name : "";
+}
+
+/* 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 *format, ...)
+{
+ 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(), pname);
+#elif HAVE_NETBSD_PTHREAD_SETNAME_NP
+ pthread_setname_np(pthread_self(), "%s", pname);
+#elif HAVE_PTHREAD_SET_NAME_NP
+ pthread_set_name_np(pthread_self(), pname);
+#endif
+}
+
/* Returns a pointer to a string describing the program version. The
* caller must not modify or free the returned string.
*/
n = end - start;
/* Print line. */
- fprintf(stream, "%08jx ", (uintmax_t) ROUND_DOWN(ofs, per_line));
+ fprintf(stream, "%08"PRIxMAX" ", (uintmax_t) ROUND_DOWN(ofs, per_line));
for (i = 0; i < start; i++)
fprintf(stream, " ");
for (; i < end; i++)
- fprintf(stream, "%02hhx%c",
+ fprintf(stream, "%02x%c",
buf[i - start], i == per_line / 2 - 1? '-' : ' ');
if (ascii)
{
}
/* 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); \
count -= X; \
n = k; \
}
+ CTZ_STEP(32);
CTZ_STEP(16);
CTZ_STEP(8);
CTZ_STEP(4);
#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
#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. */
n_bits);
return ntohll(value);
}
+\f
+/* 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;
+}
+