/* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * rseq implementation */ #include #ifdef _KERNEL #include #include #include static long rseq_random(); #define random rseq_random #else #include #define ASSERT assert #include #endif /*ARGSUSED*/ static int rseq_do_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err, uintptr_t fail_num) { int i; rseq_step_t *s; int rval = RSEQ_OK; for (i = 0; i < num; i++) { s = &rseq[i].r_do; if (s->s_func == NULL) { continue; } s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err; rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK; if (rval == RSEQ_UNDO) { (void) rseq_undo(rseq, i, arg, flags); break; } else if (rval == RSEQ_ABORT) { break; } ASSERT(rval == RSEQ_OK); } return (rval); } /*ARGSUSED*/ static int rseq_undo_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err, uintptr_t fail_num) { int i; rseq_step_t *s; int rval = RSEQ_OK; for (i = num - 1; i >= 0; i--) { s = &rseq[i].r_undo; if (s->s_func == NULL) { continue; } s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err; rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK; if (rval == RSEQ_ABORT) { break; } ASSERT(rval == RSEQ_OK); } return (rval); } int rseq_do(rseq_t *rseq, int num, uintptr_t arg, int flags) { return (rseq_do_common(rseq, num, arg, flags, 0, -1)); } int rseq_undo(rseq_t *rseq, int num, uintptr_t arg, int flags) { return (rseq_undo_common(rseq, num, arg, flags, 0, -1)); } #ifdef DEBUG #ifndef __lock_lint static int rseq_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario, uintptr_t sarg1, uintptr_t sarg2, int (*func)(rseq_t *, int, uintptr_t, int, int, uintptr_t)) { int rnd, rval = RSEQ_OK, i; switch (scenario) { case RSEQ_DBG_FAIL_ONE: rval = func(rseq, num, arg, flags, sarg1, sarg2); break; case RSEQ_DBG_FAIL_ONE_RANDOM: rnd = random() % num; rval = func(rseq, num, arg, flags, sarg1, rnd); break; case RSEQ_DBG_FAIL_ONEBYONE: for (i = 0; i < num; i++) { rval = func(rseq, num, arg, flags, sarg1, i); /* * when aborted, the undo path is not executed, so we * can't continue without the risk of resource leakage. */ if (rval == RSEQ_ABORT) { break; } } break; default: ASSERT(!"rseq_debug: incorrect debug scenario"); rval = RSEQ_ABORT; } return (rval); } int rseq_do_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario, uintptr_t sarg1, uintptr_t sarg2) { return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2, rseq_do_common)); } int rseq_undo_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario, uintptr_t sarg1, uintptr_t sarg2) { return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2, rseq_undo_common)); } #ifdef _KERNEL static long rseq_random() { return (ddi_get_lbolt()); } #endif /* _KERNEL */ #endif /* __lock_lint */ #endif /* DEBUG */