Changeset 1a3b953 in mainline for uspace/lib/bithenge/failure.c
- Timestamp:
- 2012-08-20T00:22:19Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0784869
- Parents:
- 5e514c0
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/bithenge/failure.c
r5e514c0 r1a3b953 36 36 37 37 #include <errno.h> 38 #include <execinfo.h> 38 39 #include <fcntl.h> 39 40 #include <stdio.h> … … 45 46 #define BITHENGE_FAILURE_DECLS_ONLY 1 46 47 #include "failure.h" 48 #include "os.h" 47 49 48 50 /* This file raises fake errors from system calls, to test that Bithenge … … 54 56 * correctly (exit code is 1), the main process continues without errors. If 55 57 * the child process has a problem, the main process raises the fake error 56 * again and shows all stdout and stderr output. For speed, failures only occur57 * for some system calls after the first 128.58 * again and shows all stdout and stderr output. For speed, errors are only 59 * raised when part of the backtrace has not been seen before. 58 60 * 59 61 * BITHENGE_FAILURE_INDEX set: the program runs normally until system call … … 61 63 * call. */ 62 64 65 static int g_initialized = 0; 63 66 static int g_failure_index = -1; 64 static int g_failure_index_selected = -2; 65 66 static int should_fail(void) 67 static int g_failure_index_selected = -1; 68 69 typedef struct backtrace_item { 70 struct backtrace_item *next; 71 void *backtrace_item; 72 } backtrace_item_t; 73 74 static backtrace_item_t *g_backtrace_items = NULL; 75 76 static void atexit_handler(void) 77 { 78 while (g_backtrace_items) { 79 backtrace_item_t *first = g_backtrace_items; 80 g_backtrace_items = first->next; 81 free(first); 82 } 83 } 84 85 static inline void initialize(void) 86 { 87 g_initialized = 1; 88 int rc = atexit(atexit_handler); 89 if (rc) 90 exit(127); 91 92 char *sel_str = getenv("BITHENGE_FAILURE_INDEX"); 93 if (sel_str) 94 g_failure_index_selected = strtol(sel_str, NULL, 10); 95 } 96 97 /* Record a hit for a backtrace address and return whether this is the first 98 * hit. */ 99 static inline int backtrace_item_hit(void *addr) 100 { 101 backtrace_item_t **bip; 102 for (bip = &g_backtrace_items; *bip; bip = &(*bip)->next) { 103 backtrace_item_t *bi = *bip; 104 if (bi->backtrace_item == addr) { 105 /* Keep frequently accessed items near the front. */ 106 *bip = bi->next; 107 bi->next = g_backtrace_items; 108 g_backtrace_items = bi; 109 return 0; 110 } 111 } 112 113 /* No item found; create one. */ 114 backtrace_item_t *i = malloc(sizeof(*i)); 115 if (!i) 116 exit(127); 117 i->next = g_backtrace_items; 118 i->backtrace_item = addr; 119 g_backtrace_items = i; 120 return 1; 121 } 122 123 int bithenge_should_fail(void) 67 124 { 68 125 g_failure_index++; 69 126 70 if (g_failure_index_selected == -2) { 71 char *sel_str = getenv("BITHENGE_FAILURE_INDEX"); 72 if (sel_str) { 73 g_failure_index_selected = strtol(sel_str, NULL, 10); 74 } else { 75 g_failure_index_selected = -1; 76 } 77 } else if (g_failure_index_selected != -1) { 127 if (!g_initialized) 128 initialize(); 129 130 if (g_failure_index_selected != -1) { 78 131 if (g_failure_index == g_failure_index_selected) 79 132 return 1; /* breakpoint here */ … … 81 134 } 82 135 83 /* Only fail half the time after 128 failures, 1/4 the time after 256 84 * failures, 1/8 the time after 512 failures... */ 85 int index = g_failure_index; 86 while (index >= 128) { 87 int test = (index & (64 | 1)); 88 if (test == (64 | 1) || test == 0) 89 return 0; 90 index >>= 1; 91 } 136 /* If all backtrace items have been seen already, there's no need to 137 * try raising an error. */ 138 void *trace[256]; 139 int size = backtrace(trace, 256); 140 int raise_error = 0; 141 for (int i = 0; i < size; i++) { 142 if (backtrace_item_hit(trace[i])) 143 raise_error = 1; 144 } 145 if (!raise_error) 146 return 0; 92 147 93 148 if (!fork()) { 94 /* Child */149 /* Child silently fails. */ 95 150 int null = open("/dev/null", O_WRONLY); 96 151 if (null == -1) … … 102 157 } 103 158 104 /* Parent */159 /* Parent checks whether child failed correctly. */ 105 160 int status; 106 161 wait(&status); … … 108 163 return 0; 109 164 110 /* The child had an error! We couldn't see it because stdout and stderr111 * were redirected, and we couldn't debug it easily because it was a112 * separate process. Do it againwithout redirecting or forking. */165 /* The child had an error! We couldn't easily debug it because it was 166 * in a separate process with redirected stdout and stderr. Do it again 167 * without redirecting or forking. */ 113 168 fprintf(stderr, "** Fake error raised here (BITHENGE_FAILURE_INDEX=%d)\n", 114 169 g_failure_index); … … 118 173 void *bithenge_failure_malloc(size_t size) 119 174 { 120 if ( should_fail())175 if (bithenge_should_fail()) 121 176 return NULL; 122 177 return malloc(size); … … 125 180 void *bithenge_failure_realloc(void *ptr, size_t size) 126 181 { 127 if ( should_fail())182 if (bithenge_should_fail()) 128 183 return NULL; 129 184 return realloc(ptr, size); … … 132 187 ssize_t bithenge_failure_read(int fd, void *buf, size_t count) 133 188 { 134 if ( should_fail()) {189 if (bithenge_should_fail()) { 135 190 errno = EIO; 136 191 return -1; … … 141 196 off_t bithenge_failure_lseek(int fd, off_t offset, int whither) 142 197 { 143 if ( should_fail()) {198 if (bithenge_should_fail()) { 144 199 errno = EINVAL; 145 200 return (off_t) -1; … … 148 203 } 149 204 205 int bithenge_failure_ferror(FILE *stream) 206 { 207 if (bithenge_should_fail()) 208 return 1; 209 return ferror(stream); 210 } 211 212 char *bithenge_failure_str_ndup(const char *s, size_t max_len) 213 { 214 if (bithenge_should_fail()) 215 return NULL; 216 return str_ndup(s, max_len); 217 } 218 219 int bithenge_failure_open(const char *pathname, int flags) 220 { 221 if (bithenge_should_fail()) { 222 errno = EACCES; 223 return -1; 224 } 225 return open(pathname, flags); 226 } 227 228 int bithenge_failure_fstat(int fd, struct stat *buf) 229 { 230 if (bithenge_should_fail()) { 231 errno = EIO; 232 return -1; 233 } 234 return fstat(fd, buf); 235 } 236 150 237 /** @} 151 238 */
Note:
See TracChangeset
for help on using the changeset viewer.