configure: Distinguish glibc and NetBSD pthread_setname_np() variants.
[sliver-openvswitch.git] / lib / util.c
index 256421a..1751c6f 100644 (file)
@@ -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 <config.h>
 #include "util.h"
-#include <assert.h>
 #include <errno.h>
 #include <limits.h>
+#include <pthread.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -28,7 +28,7 @@
 #include <unistd.h>
 #include "byte-order.h"
 #include "coverage.h"
-#include "openvswitch/types.h"
+#include "ovs-thread.h"
 #include "vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(util);
@@ -38,13 +38,40 @@ 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_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 +281,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 +311,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));
+}
+
+const char *
+ovs_strerror(int error)
+{
+    enum { BUFSIZE = sizeof strerror_buffer_get()->s };
+    int save_errno;
+    char *buffer;
+    char *s;
 
-    if (!retval) {
-        return "";
-    }
-    if (retval > 0) {
-        return strerror(retval);
-    }
-    if (retval == EOF) {
-        return "End of file";
+    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 +367,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 +386,30 @@ 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 '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.) */
+void
+set_subprogram_name(const char *name)
+{
+    free(subprogram_name_set(xstrdup(name)));
+#if HAVE_GLIBC_PTHREAD_SETNAME_NP
+    pthread_setname_np(pthread_self(), name);
+#elif HAVE_NETBSD_PTHREAD_SETNAME_NP
+    pthread_setname_np(pthread_self(), "%s", name);
+#elif HAVE_PTHREAD_SET_NAME_NP
+    pthread_set_name_np(pthread_self(), name);
+#endif
+}
+
 /* Returns a pointer to a string describing the program version.  The
  * caller must not modify or free the returned string.
  */
@@ -564,7 +641,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 +779,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 +834,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,44 +865,40 @@ 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;
-#endif
-    }
+    return count;
 }
+#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