Initial Linux ZFS GIT Repo
[zfs.git] / zfs / lib / libumem / umem_fail.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * Portions Copyright 2006 OmniTI, Inc.
28  */
29
30 /* #pragma ident        "@(#)umem_fail.c        1.4     05/06/08 SMI" */
31
32 /*
33  * Failure routines for libumem (not standalone)
34  */
35
36 #include "config.h"
37 #include <sys/types.h>
38 #include <signal.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <stdio.h>
42
43 #include "misc.h"
44
45 static volatile int umem_exiting = 0;
46 #define UMEM_EXIT_ABORT 1
47
48 static mutex_t umem_exit_lock = DEFAULTMUTEX; /* protects umem_exiting */
49
50 static int
51 firstexit(int type)
52 {
53         if (umem_exiting)
54                 return (0);
55
56         (void) mutex_lock(&umem_exit_lock);
57         if (umem_exiting) {
58                 (void) mutex_unlock(&umem_exit_lock);
59                 return (0);
60         }
61         umem_exiting = type;
62         (void) mutex_unlock(&umem_exit_lock);
63
64         return (1);
65 }
66
67 /*
68  * We can't use abort(3C), since it closes all of the standard library
69  * FILEs, which can call free().
70  *
71  * In addition, we can't just raise(SIGABRT), since the current handler
72  * might do allocation.  We give them once chance, though.
73  */
74 static void __NORETURN
75 umem_do_abort(void)
76 {
77 #ifdef _WIN32
78         abort();
79 #else
80         if (firstexit(UMEM_EXIT_ABORT)) {
81                 (void) raise(SIGABRT);
82         }
83
84         for (;;) {
85 #if defined(__FreeBSD__)
86                 sigset_t set;
87                 struct sigaction sa;
88
89                 sa.sa_handler = SIG_DFL;
90                 (void) sigaction(SIGABRT, &sa, NULL);
91                 (void) sigemptyset (&set);
92                 (void) sigaddset (&set, SIGABRT);
93                 (void) sigprocmask (SIG_UNBLOCK, &set, NULL);
94                 (void) raise (SIGABRT);
95 #else
96                 (void) signal(SIGABRT, SIG_DFL);
97                 (void) sigrelse(SIGABRT);
98                 (void) raise(SIGABRT);
99 #endif
100         }
101 #endif
102 }
103
104 #define SKIP_FRAMES             1       /* skip the panic frame */
105 #define ERR_STACK_FRAMES        128
106
107 static void
108 print_stacktrace(void)
109 {
110         uintptr_t cur_stack[ERR_STACK_FRAMES];
111
112         /*
113          * if we are in a signal context, checking for it will recurse
114          */
115         uint_t nframes = getpcstack(cur_stack, ERR_STACK_FRAMES, 0);
116         uint_t idx;
117
118         if (nframes > SKIP_FRAMES) {
119                 umem_printf("stack trace:\n");
120
121                 for (idx = SKIP_FRAMES; idx < nframes; idx++) {
122                         (void) print_sym((void *)cur_stack[idx]);
123                         umem_printf("\n");
124                 }
125         }
126 }
127
128 void
129 umem_panic(const char *format, ...)
130 {
131         va_list va;
132
133         va_start(va, format);
134         umem_vprintf(format, va);
135         va_end(va);
136
137         if (format[strlen(format)-1] != '\n')
138                 umem_error_enter("\n");
139
140 #ifdef ECELERITY
141         va_start(va, format);
142         ec_debug_vprintf(DCRITICAL, DMEM, format, va);
143         va_end(va);
144 #endif
145         
146         print_stacktrace();
147
148         umem_do_abort();
149 }
150
151 void
152 umem_err_recoverable(const char *format, ...)
153 {
154         va_list va;
155
156         va_start(va, format);
157         umem_vprintf(format, va);
158         va_end(va);
159
160         if (format[strlen(format)-1] != '\n')
161                 umem_error_enter("\n");
162
163         print_stacktrace();
164
165         if (umem_abort > 0)
166                 umem_do_abort();
167 }
168
169 int
170 __umem_assert_failed(const char *assertion, const char *file, int line)
171 {
172         umem_panic("Assertion failed: %s, file %s, line %d\n",
173             assertion, file, line);
174         umem_do_abort();
175         /*NOTREACHED*/
176 }