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 2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * rseq implementation 31 */ 32 33 #include <sys/usb/clients/usbser/usbser_rseq.h> 34 35 #ifdef _KERNEL 36 #include <sys/debug.h> 37 #include <sys/ddi.h> 38 #include <sys/sunddi.h> 39 static long rseq_random(); 40 #define random rseq_random 41 #else 42 #include <assert.h> 43 #define ASSERT assert 44 #include <stdlib.h> 45 #endif 46 47 48 /*ARGSUSED*/ 49 static int 50 rseq_do_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err, 51 uintptr_t fail_num) 52 { 53 int i; 54 rseq_step_t *s; 55 int rval = RSEQ_OK; 56 57 for (i = 0; i < num; i++) { 58 s = &rseq[i].r_do; 59 60 if (s->s_func == NULL) { 61 continue; 62 } 63 s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err; 64 rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK; 65 66 if (rval == RSEQ_UNDO) { 67 (void) rseq_undo(rseq, i, arg, flags); 68 break; 69 } else if (rval == RSEQ_ABORT) { 70 break; 71 } 72 ASSERT(rval == RSEQ_OK); 73 } 74 return (rval); 75 } 76 77 78 /*ARGSUSED*/ 79 static int 80 rseq_undo_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err, 81 uintptr_t fail_num) 82 { 83 int i; 84 rseq_step_t *s; 85 int rval = RSEQ_OK; 86 87 for (i = num - 1; i >= 0; i--) { 88 s = &rseq[i].r_undo; 89 90 if (s->s_func == NULL) { 91 continue; 92 } 93 s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err; 94 rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK; 95 96 if (rval == RSEQ_ABORT) { 97 break; 98 } 99 ASSERT(rval == RSEQ_OK); 100 } 101 return (rval); 102 } 103 104 105 int 106 rseq_do(rseq_t *rseq, int num, uintptr_t arg, int flags) 107 { 108 return (rseq_do_common(rseq, num, arg, flags, 0, -1)); 109 } 110 111 112 int 113 rseq_undo(rseq_t *rseq, int num, uintptr_t arg, int flags) 114 { 115 return (rseq_undo_common(rseq, num, arg, flags, 0, -1)); 116 } 117 118 #ifdef DEBUG 119 120 #ifndef __lock_lint 121 122 static int 123 rseq_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario, 124 uintptr_t sarg1, uintptr_t sarg2, 125 int (*func)(rseq_t *, int, uintptr_t, int, int, uintptr_t)) 126 { 127 int rnd, rval, i; 128 129 switch (scenario) { 130 case RSEQ_DBG_FAIL_ONE: 131 rval = func(rseq, num, arg, flags, sarg1, sarg2); 132 break; 133 case RSEQ_DBG_FAIL_ONE_RANDOM: 134 rnd = random() % num; 135 rval = func(rseq, num, arg, flags, sarg1, rnd); 136 break; 137 case RSEQ_DBG_FAIL_ONEBYONE: 138 for (i = 0; i < num; i++) { 139 rval = func(rseq, num, arg, flags, sarg1, i); 140 /* 141 * when aborted, the undo path is not executed, so we 142 * can't continue without the risk of resource leakage. 143 */ 144 if (rval == RSEQ_ABORT) { 145 break; 146 } 147 } 148 break; 149 default: 150 ASSERT(!"rseq_debug: incorrect debug scenario"); 151 } 152 return (rval); 153 } 154 155 156 int 157 rseq_do_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario, 158 uintptr_t sarg1, uintptr_t sarg2) 159 { 160 return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2, 161 rseq_do_common)); 162 } 163 164 165 int 166 rseq_undo_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario, 167 uintptr_t sarg1, uintptr_t sarg2) 168 { 169 return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2, 170 rseq_undo_common)); 171 } 172 173 #ifdef _KERNEL 174 static long 175 rseq_random() 176 { 177 return (ddi_get_lbolt()); 178 } 179 #endif /* _KERNEL */ 180 181 #endif /* __lock_lint */ 182 183 #endif /* DEBUG */ 184