X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Futil.c;h=1bb5096b0f65a8fe3772738176a336b1d830d570;hb=5fcbed7479c5f1d2cc08c3f544f10dbbe8ec0d90;hp=f9880f351ff8ca14870ca5589fd2fb7f9e18ca4e;hpb=79a010aa803dc43c7a2d70046f0ad4a2d4cb4a11;p=sliver-openvswitch.git diff --git a/lib/util.c b/lib/util.c index f9880f351..1bb5096b0 100644 --- a/lib/util.c +++ b/lib/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,27 +16,62 @@ #include #include "util.h" -#include #include #include +#include #include #include #include #include #include +#include #include #include "byte-order.h" #include "coverage.h" -#include "openvswitch/types.h" +#include "ovs-thread.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(util); COVERAGE_DEFINE(util_xalloc); +/* 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 = ""; + +/* --version option output. */ static char *program_version; +/* Buffer used by ovs_strerror(). */ +DEFINE_PER_THREAD_DATA(struct { char s[128]; }, strerror_buffer, { "" }); + +void +ovs_assert_failure(const char *where, const char *function, + const char *condition) +{ + /* Prevent an infinite loop (or stack overflow) in case VLOG_ABORT happens + * to trigger an assertion failure of its own. */ + static int reentry = 0; + + switch (reentry++) { + case 0: + VLOG_ABORT("%s: assertion %s failed in %s()", + where, condition, function); + NOT_REACHED(); + + case 1: + fprintf(stderr, "%s: assertion %s failed in %s()", + where, condition, function); + abort(); + + default: + abort(); + } +} + void out_of_memory(void) { @@ -192,9 +227,14 @@ ovs_abort(int err_no, const char *format, ...) va_list args; va_start(args, format); - ovs_error_valist(err_no, format, args); - va_end(args); + ovs_abort_valist(err_no, format, args); +} +/* Same as ovs_abort() except that the arguments are supplied as a va_list. */ +void +ovs_abort_valist(int err_no, const char *format, va_list args) +{ + ovs_error_valist(err_no, format, args); abort(); } @@ -243,7 +283,12 @@ ovs_error_valist(int err_no, const char *format, va_list args) { int save_errno = errno; - fprintf(stderr, "%s: ", program_name); + if (subprogram_name[0]) { + fprintf(stderr, "%s(%s): ", program_name, subprogram_name); + } else { + fprintf(stderr, "%s: ", program_name); + } + vfprintf(stderr, format, args); if (err_no != 0) { fprintf(stderr, " (%s)", ovs_retval_to_string(err_no)); @@ -265,19 +310,41 @@ ovs_error_valist(int err_no, const char *format, va_list args) const char * ovs_retval_to_string(int retval) { - static char unknown[48]; + return (!retval ? "" + : retval == EOF ? "End of file" + : ovs_strerror(retval)); +} - if (!retval) { - return ""; - } - if (retval > 0) { - return strerror(retval); - } - if (retval == EOF) { - return "End of file"; +const char * +ovs_strerror(int error) +{ + enum { BUFSIZE = sizeof strerror_buffer_get()->s }; + int save_errno; + char *buffer; + char *s; + + save_errno = errno; + buffer = strerror_buffer_get()->s; + +#if STRERROR_R_CHAR_P + /* GNU style strerror_r() might return an immutable static string, or it + * might write and return 'buffer', but in either case we can pass the + * returned string directly to the caller. */ + s = strerror_r(error, buffer, BUFSIZE); +#else /* strerror_r() returns an int. */ + s = buffer; + if (strerror_r(error, buffer, BUFSIZE)) { + /* strerror_r() is only allowed to fail on ERANGE (because the buffer + * 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(unknown, sizeof unknown, "***unknown return value: %d***", retval); - return unknown; +#endif + + errno = save_errno; + + return s; } /* Sets global "program_name" and "program_version" variables. Should @@ -299,6 +366,9 @@ set_program_name__(const char *argv0, const char *version, const char *date, const char *time) { const char *slash = strrchr(argv0, '/'); + + assert_single_threaded(); + program_name = slash ? slash + 1 : argv0; free(program_version); @@ -630,6 +700,90 @@ abs_file_name(const char *dir, const char *file_name) } } +/* Like readlink(), but returns the link name as a null-terminated string in + * allocated memory that the caller must eventually free (with free()). + * Returns NULL on error, in which case errno is set appropriately. */ +char * +xreadlink(const char *filename) +{ + size_t size; + + for (size = 64; ; size *= 2) { + char *buf = xmalloc(size); + ssize_t retval = readlink(filename, buf, size); + int error = errno; + + if (retval >= 0 && retval < size) { + buf[retval] = '\0'; + return buf; + } + + free(buf); + if (retval < 0) { + errno = error; + return NULL; + } + } +} + +/* Returns a version of 'filename' with symlinks in the final component + * dereferenced. This differs from realpath() in that: + * + * - 'filename' need not exist. + * + * - If 'filename' does exist as a symlink, its referent need not exist. + * + * - Only symlinks in the final component of 'filename' are dereferenced. + * + * The caller must eventually free the returned string (with free()). */ +char * +follow_symlinks(const char *filename) +{ + struct stat s; + char *fn; + int i; + + fn = xstrdup(filename); + for (i = 0; i < 10; i++) { + char *linkname; + char *next_fn; + + if (lstat(fn, &s) != 0 || !S_ISLNK(s.st_mode)) { + return fn; + } + + linkname = xreadlink(fn); + if (!linkname) { + VLOG_WARN("%s: readlink failed (%s)", filename, strerror(errno)); + return fn; + } + + if (linkname[0] == '/') { + /* Target of symlink is absolute so use it raw. */ + next_fn = linkname; + } else { + /* Target of symlink is relative so add to 'fn''s directory. */ + char *dir = dir_name(fn); + + if (!strcmp(dir, ".")) { + next_fn = linkname; + } else { + char *separator = dir[strlen(dir) - 1] == '/' ? "" : "/"; + next_fn = xasprintf("%s%s%s", dir, separator, linkname); + free(linkname); + } + + free(dir); + } + + free(fn); + fn = next_fn; + } + + VLOG_WARN("%s: too many levels of symlinks", filename); + free(fn); + return xstrdup(filename); +} /* Pass a value to this function if it is marked with * __attribute__((warn_unused_result)) and you genuinely want to ignore @@ -654,7 +808,7 @@ english_list_delimiter(size_t index, size_t total) int log_2_floor(uint32_t n) { - assert(n); + ovs_assert(n); #if !defined(UINT_MAX) || !defined(UINT32_MAX) #error "Someone screwed up the #includes." @@ -685,40 +839,70 @@ log_2_floor(uint32_t n) int log_2_ceil(uint32_t n) { - return log_2_floor(n) + !IS_POW2(n); + return log_2_floor(n) + !is_pow2(n); } -/* Returns the number of trailing 0-bits in 'n', or 32 if 'n' is 0. */ -int -ctz(uint32_t n) -{ - if (!n) { - return 32; - } else { +/* 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 - return __builtin_ctz(n); +/* Defined inline in util.h. */ #else - unsigned int k; - int count = 31; +static int +raw_ctz(uint32_t n) +{ + unsigned int k; + int count = 31; #define CTZ_STEP(X) \ - k = n << (X); \ - if (k) { \ - count -= X; \ - n = k; \ - } - CTZ_STEP(16); - CTZ_STEP(8); - CTZ_STEP(4); - CTZ_STEP(2); - CTZ_STEP(1); + k = n << (X); \ + if (k) { \ + count -= X; \ + n = k; \ + } + CTZ_STEP(16); + CTZ_STEP(8); + CTZ_STEP(4); + CTZ_STEP(2); + CTZ_STEP(1); #undef CTZ_STEP - return count; + return count; +} #endif - } + +/* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */ +unsigned int +popcount(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 + * __builtin_popcount(), although nonportable asm("popcnt") was over 50% + * faster. */ +#define INIT1(X) \ + ((((X) & (1 << 0)) != 0) + \ + (((X) & (1 << 1)) != 0) + \ + (((X) & (1 << 2)) != 0) + \ + (((X) & (1 << 3)) != 0) + \ + (((X) & (1 << 4)) != 0) + \ + (((X) & (1 << 5)) != 0) + \ + (((X) & (1 << 6)) != 0) + \ + (((X) & (1 << 7)) != 0)) +#define INIT2(X) INIT1(X), INIT1((X) + 1) +#define INIT4(X) INIT2(X), INIT2((X) + 2) +#define INIT8(X) INIT4(X), INIT4((X) + 4) +#define INIT16(X) INIT8(X), INIT8((X) + 8) +#define INIT32(X) INIT16(X), INIT16((X) + 16) +#define INIT64(X) INIT32(X), INIT32((X) + 32) + + static const uint8_t popcount8[256] = { + INIT64(0), INIT64(64), INIT64(128), INIT64(192) + }; + + return (popcount8[x & 0xff] + + popcount8[(x >> 8) & 0xff] + + popcount8[(x >> 16) & 0xff] + + popcount8[x >> 24]); } /* Returns true if the 'n' bytes starting at 'p' are zeros. */