X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Futil.c;h=a32c80aaafd08729ca886e46765c132f5f73f447;hb=24b7e19469dbd2cb3fdf8db70ef0c7b4bc851f17;hp=c90d556c316a3ef5e5b49bbcc8dad8762993d4b7;hpb=0ee140fb69ec924fe5280c1ceaa82c7a3d8f4223;p=sliver-openvswitch.git diff --git a/lib/util.c b/lib/util.c index c90d556c3..a32c80aaa 100644 --- a/lib/util.c +++ b/lib/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * 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,9 +16,9 @@ #include #include "util.h" -#include #include #include +#include #include #include #include @@ -28,8 +28,11 @@ #include #include "byte-order.h" #include "coverage.h" -#include "openvswitch/types.h" +#include "ovs-thread.h" #include "vlog.h" +#ifdef HAVE_PTHREAD_SET_NAME_NP +#include +#endif VLOG_DEFINE_THIS_MODULE(util); @@ -38,13 +41,42 @@ 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 = ""; +/* 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_STATIC_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) { @@ -254,6 +286,7 @@ ovs_error(int err_no, const char *format, ...) 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]) { @@ -283,19 +316,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 @@ -317,6 +372,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); @@ -333,6 +391,43 @@ set_program_name__(const char *argv0, const char *version, const char *date, } } +/* 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. */ @@ -564,7 +659,7 @@ get_cwd(void) int error = errno; free(buf); if (error != ERANGE) { - VLOG_WARN("getcwd failed (%s)", strerror(error)); + VLOG_WARN("getcwd failed (%s)", ovs_strerror(error)); return NULL; } size *= 2; @@ -702,7 +797,8 @@ follow_symlinks(const char *filename) linkname = xreadlink(fn); if (!linkname) { - VLOG_WARN("%s: readlink failed (%s)", filename, strerror(errno)); + VLOG_WARN("%s: readlink failed (%s)", + filename, ovs_strerror(errno)); return fn; } @@ -756,7 +852,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." @@ -787,7 +883,7 @@ 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'. Undefined if 'n' == 0. */ @@ -820,7 +916,7 @@ raw_ctz(uint32_t n) #endif /* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */ -int +unsigned int popcount(uint32_t x) { /* In my testing, this implementation is over twice as fast as any other