freebsd-dev/lib/libuutil/uu_misc.c
Brian Behlendorf 1e33ac1e26 Fix Solaris thread dependency by using pthreads
This is a portability change which removes the dependence of the Solaris
thread library.  All locations where Solaris thread API was used before
have been replaced with equivilant Solaris kernel style thread calls.
In user space the kernel style threading API is implemented in term of
the portable pthreads library.  This includes all threads, mutexs,
condition variables, reader/writer locks, and taskqs.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
2010-08-31 08:38:47 -07:00

292 lines
6.4 KiB
C

/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include "libuutil_common.h"
#include <assert.h>
#include <errno.h>
#include <libintl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/debug.h>
#include <unistd.h>
#include <ctype.h>
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
/*
* All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
* is here to enable the building of a native version of
* libuutil.so when the build machine has not yet been upgraded
* to a version of libc that provides pthread_key_create_once_np().
* It should all be deleted when solaris_nevada ships.
* The code is not MT-safe in a relaxed memory model.
*/
#if defined(PTHREAD_ONCE_KEY_NP)
static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;
#else /* PTHREAD_ONCE_KEY_NP */
static pthread_key_t uu_error_key = 0;
static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
#endif /* PTHREAD_ONCE_KEY_NP */
static int uu_error_key_setup = 0;
static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
/* LINTED static unused */
static const char *uu_panic_format;
/* LINTED static unused */
static va_list uu_panic_args;
static pthread_t uu_panic_thread;
static uint32_t _uu_main_error;
static __thread int _uu_main_thread = 0;
void
uu_set_error(uint_t code)
{
if (_uu_main_thread) {
_uu_main_error = code;
return;
}
#if defined(PTHREAD_ONCE_KEY_NP)
if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
uu_error_key_setup = -1;
else
uu_error_key_setup = 1;
#else /* PTHREAD_ONCE_KEY_NP */
if (uu_error_key_setup == 0) {
(void) pthread_mutex_lock(&uu_key_lock);
if (uu_error_key_setup == 0) {
if (pthread_key_create(&uu_error_key, NULL) != 0)
uu_error_key_setup = -1;
else
uu_error_key_setup = 1;
}
(void) pthread_mutex_unlock(&uu_key_lock);
}
#endif /* PTHREAD_ONCE_KEY_NP */
if (uu_error_key_setup > 0)
(void) pthread_setspecific(uu_error_key,
(void *)(uintptr_t)code);
}
uint32_t
uu_error(void)
{
if (_uu_main_thread)
return (_uu_main_error);
if (uu_error_key_setup < 0) /* can't happen? */
return (UU_ERROR_UNKNOWN);
/*
* Because UU_ERROR_NONE == 0, if uu_set_error() was
* never called, then this will return UU_ERROR_NONE:
*/
return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
}
const char *
uu_strerror(uint32_t code)
{
const char *str;
switch (code) {
case UU_ERROR_NONE:
str = dgettext(TEXT_DOMAIN, "No error");
break;
case UU_ERROR_INVALID_ARGUMENT:
str = dgettext(TEXT_DOMAIN, "Invalid argument");
break;
case UU_ERROR_UNKNOWN_FLAG:
str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
break;
case UU_ERROR_NO_MEMORY:
str = dgettext(TEXT_DOMAIN, "Out of memory");
break;
case UU_ERROR_CALLBACK_FAILED:
str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
break;
case UU_ERROR_NOT_SUPPORTED:
str = dgettext(TEXT_DOMAIN, "Operation not supported");
break;
case UU_ERROR_EMPTY:
str = dgettext(TEXT_DOMAIN, "No value provided");
break;
case UU_ERROR_UNDERFLOW:
str = dgettext(TEXT_DOMAIN, "Value too small");
break;
case UU_ERROR_OVERFLOW:
str = dgettext(TEXT_DOMAIN, "Value too large");
break;
case UU_ERROR_INVALID_CHAR:
str = dgettext(TEXT_DOMAIN,
"Value contains unexpected character");
break;
case UU_ERROR_INVALID_DIGIT:
str = dgettext(TEXT_DOMAIN,
"Value contains digit not in base");
break;
case UU_ERROR_SYSTEM:
str = dgettext(TEXT_DOMAIN, "Underlying system error");
break;
case UU_ERROR_UNKNOWN:
str = dgettext(TEXT_DOMAIN, "Error status not known");
break;
default:
errno = ESRCH;
str = NULL;
break;
}
return (str);
}
void
uu_panic(const char *format, ...)
{
va_list args;
va_start(args, format);
(void) pthread_mutex_lock(&uu_panic_lock);
if (uu_panic_thread == 0) {
uu_panic_thread = pthread_self();
uu_panic_format = format;
va_copy(uu_panic_args, args);
}
(void) pthread_mutex_unlock(&uu_panic_lock);
(void) vfprintf(stderr, format, args);
if (uu_panic_thread == pthread_self())
abort();
else
for (;;)
(void) pause();
}
int
assfail(const char *astring, const char *file, int line)
{
#if defined(__STDC__) && __STDC_VERSION__ - 0 >= 199901L
__assert_c99(astring, file, line, "unknown func");
#else
__assert(astring, file, line);
#endif
/*NOTREACHED*/
return (0);
}
static void
uu_lockup(void)
{
(void) pthread_mutex_lock(&uu_panic_lock);
#if !defined(PTHREAD_ONCE_KEY_NP)
(void) pthread_mutex_lock(&uu_key_lock);
#endif
uu_avl_lockup();
uu_list_lockup();
}
static void
uu_release(void)
{
(void) pthread_mutex_unlock(&uu_panic_lock);
#if !defined(PTHREAD_ONCE_KEY_NP)
(void) pthread_mutex_unlock(&uu_key_lock);
#endif
uu_avl_release();
uu_list_release();
}
static void
uu_release_child(void)
{
uu_panic_format = NULL;
uu_panic_thread = 0;
uu_release();
}
#ifdef __GNUC__
static void
uu_init(void) __attribute__((constructor));
#else
#pragma init(uu_init)
#endif
static void
uu_init(void)
{
_uu_main_thread = 1;
(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
}
/*
* Dump a block of memory in hex+ascii, for debugging
*/
void
uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
{
const unsigned char *p = buf;
int i;
for (i = 0; i < len; i += 16) {
int j;
(void) fprintf(out, "%s", prefix);
for (j = 0; j < 16 && i + j < len; j++) {
(void) fprintf(out, "%2.2x ", p[i + j]);
}
for (; j < 16; j++) {
(void) fprintf(out, " ");
}
for (j = 0; j < 16 && i + j < len; j++) {
(void) fprintf(out, "%c",
isprint(p[i + j]) ? p[i + j] : '.');
}
(void) fprintf(out, "\n");
}
}