Index: head/sys/amd64/amd64/db_trace.c =================================================================== --- head/sys/amd64/amd64/db_trace.c (revision 6805) +++ head/sys/amd64/amd64/db_trace.c (revision 6806) @@ -1,340 +1,340 @@ /* * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: db_trace.c,v 1.7 1994/08/06 10:25:33 davidg Exp $ + * $Id: db_trace.c,v 1.8 1994/08/13 03:49:37 wollman Exp $ */ #include #include +#include #include #include #include #include #include -#include #include #include #include #include /* * Machine register set. */ struct db_variable db_regs[] = { "cs", (int *)&ddb_regs.tf_cs, FCN_NULL, "ds", (int *)&ddb_regs.tf_ds, FCN_NULL, "es", (int *)&ddb_regs.tf_es, FCN_NULL, #if 0 "fs", (int *)&ddb_regs.tf_fs, FCN_NULL, "gs", (int *)&ddb_regs.tf_gs, FCN_NULL, #endif "ss", (int *)&ddb_regs.tf_ss, FCN_NULL, "eax", (int *)&ddb_regs.tf_eax, FCN_NULL, "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL, "edx", (int *)&ddb_regs.tf_edx, FCN_NULL, "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL, "esp", (int *)&ddb_regs.tf_esp,FCN_NULL, "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL, "esi", (int *)&ddb_regs.tf_esi, FCN_NULL, "edi", (int *)&ddb_regs.tf_edi, FCN_NULL, "eip", (int *)&ddb_regs.tf_eip, FCN_NULL, "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); /* * Stack trace. */ #define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS) struct i386_frame { struct i386_frame *f_frame; int f_retaddr; int f_arg0; }; #define TRAP 1 #define INTERRUPT 2 #define SYSCALL 3 db_addr_t db_trap_symbol_value = 0; db_addr_t db_syscall_symbol_value = 0; db_addr_t db_kdintr_symbol_value = 0; boolean_t db_trace_symbols_found = FALSE; void db_find_trace_symbols() { db_expr_t value; if (db_value_of_name("_trap", &value)) db_trap_symbol_value = (db_addr_t) value; if (db_value_of_name("_kdintr", &value)) db_kdintr_symbol_value = (db_addr_t) value; if (db_value_of_name("_syscall", &value)) db_syscall_symbol_value = (db_addr_t) value; db_trace_symbols_found = TRUE; } /* * Figure out how many arguments were passed into the frame at "fp". */ int db_numargs(fp) struct i386_frame *fp; { int *argp; int inst; int args; extern char etext[]; argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE); if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) args = 5; else { inst = db_get_value((int)argp, 4, FALSE); if ((inst & 0xff) == 0x59) /* popl %ecx */ args = 1; else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */ args = ((inst >> 16) & 0xff) / 4; else args = 5; } return (args); } /* * Figure out the next frame up in the call stack. * For trap(), we print the address of the faulting instruction and * proceed with the calling frame. We return the ip that faulted. * If the trap was caused by jumping through a bogus pointer, then * the next line in the backtrace will list some random function as * being called. It should get the argument list correct, though. * It might be possible to dig out from the next frame up the name * of the function that faulted, but that could get hairy. */ void db_nextframe(fp, ip, argp, is_trap) struct i386_frame **fp; /* in/out */ db_addr_t *ip; /* out */ int *argp; /* in */ int is_trap; /* in */ { struct i386_saved_state *saved_regs; switch (is_trap) { case 0: *ip = (db_addr_t) db_get_value((int) &(*fp)->f_retaddr, 4, FALSE); *fp = (struct i386_frame *) db_get_value((int) &(*fp)->f_frame, 4, FALSE); break; case TRAP: default: /* * We know that trap() has 1 argument and we know that * it is an (int *). */ #if 0 saved_regs = (struct i386_saved_state *) db_get_value((int)argp, 4, FALSE); #endif saved_regs = (struct i386_saved_state *)argp; db_printf("--- trap (number %d) ---\n", saved_regs->tf_trapno & 0xffff); db_printsym(saved_regs->tf_eip, DB_STGY_XTRN); db_printf(":\n"); *fp = (struct i386_frame *)saved_regs->tf_ebp; *ip = (db_addr_t)saved_regs->tf_eip; break; case SYSCALL: { struct trapframe *saved_regs = (struct trapframe *)argp; db_printf("--- syscall (number %d) ---\n", saved_regs->tf_eax); db_printsym(saved_regs->tf_eip, DB_STGY_XTRN); db_printf(":\n"); *fp = (struct i386_frame *)saved_regs->tf_ebp; *ip = (db_addr_t)saved_regs->tf_eip; } break; } } void db_stack_trace_cmd(addr, have_addr, count, modif) db_expr_t addr; boolean_t have_addr; db_expr_t count; char *modif; { struct i386_frame *frame, *lastframe; int *argp; db_addr_t callpc; int is_trap; boolean_t kernel_only = TRUE; boolean_t trace_thread = FALSE; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { register char *cp = modif; register char c; while ((c = *cp++) != 0) { if (c == 't') trace_thread = TRUE; if (c == 'u') kernel_only = FALSE; } } if (count == -1) count = 65535; if (!have_addr) { frame = (struct i386_frame *)ddb_regs.tf_ebp; callpc = (db_addr_t)ddb_regs.tf_eip; } else if (trace_thread) { printf ("db_trace.c: can't trace thread\n"); } else { frame = (struct i386_frame *)addr; callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); } lastframe = 0; while (count-- && frame != 0) { int narg; char * name; db_expr_t offset; db_sym_t sym; #define MAXNARG 16 char *argnames[MAXNARG], **argnp = NULL; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (lastframe == 0 && sym == NULL) { /* Symbol not found, peek at code */ int instr = db_get_value(callpc, 4, FALSE); offset = 1; if ((instr & 0x00ffffff) == 0x00e58955 || /* enter: pushl %ebp, movl %esp, %ebp */ (instr & 0x0000ffff) == 0x0000e589 /* enter+1: movl %esp, %ebp */ ) { offset = 0; } } #define STRCMP(s1,s2) ((s1) && (s2) && strcmp((s1), (s2)) == 0) if (INKERNEL((int)frame) && STRCMP(name, "_trap")) { narg = 1; is_trap = TRAP; } else if (INKERNEL((int)frame) && STRCMP(name, "_kdintr")) { is_trap = INTERRUPT; narg = 0; } else if (INKERNEL((int)frame) && STRCMP(name, "_syscall")) { is_trap = SYSCALL; narg = 0; } #undef STRCMP else { is_trap = 0; narg = MAXNARG; if (db_sym_numargs(sym, &narg, argnames)) { argnp = argnames; } else { narg = db_numargs(frame); } } db_printf("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %esp instead */ argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0; } else argp = &frame->f_arg0; while (narg) { if (argnp) db_printf("%s=", *argnp++); db_printf("%x", db_get_value((int)argp, 4, FALSE)); argp++; if (--narg != 0) db_printf(","); } db_printf(") at "); db_printsym(callpc, DB_STGY_PROC); db_printf("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4); callpc = (db_addr_t)db_get_value((int)&lastframe->f_retaddr, 4, FALSE); continue; } lastframe = frame; db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap); if (frame == 0) { /* end of chain */ break; } if (INKERNEL((int)frame)) { /* staying in kernel */ if (frame <= lastframe) { db_printf("Bad frame pointer: 0x%x\n", frame); break; } } else if (INKERNEL((int)lastframe)) { /* switch from user to kernel */ if (kernel_only) break; /* kernel stack only */ } else { /* in user */ if (frame <= lastframe) { db_printf("Bad user frame pointer: 0x%x\n", frame); break; } } } } Index: head/sys/i386/i386/db_trace.c =================================================================== --- head/sys/i386/i386/db_trace.c (revision 6805) +++ head/sys/i386/i386/db_trace.c (revision 6806) @@ -1,340 +1,340 @@ /* * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: db_trace.c,v 1.7 1994/08/06 10:25:33 davidg Exp $ + * $Id: db_trace.c,v 1.8 1994/08/13 03:49:37 wollman Exp $ */ #include #include +#include #include #include #include #include #include -#include #include #include #include #include /* * Machine register set. */ struct db_variable db_regs[] = { "cs", (int *)&ddb_regs.tf_cs, FCN_NULL, "ds", (int *)&ddb_regs.tf_ds, FCN_NULL, "es", (int *)&ddb_regs.tf_es, FCN_NULL, #if 0 "fs", (int *)&ddb_regs.tf_fs, FCN_NULL, "gs", (int *)&ddb_regs.tf_gs, FCN_NULL, #endif "ss", (int *)&ddb_regs.tf_ss, FCN_NULL, "eax", (int *)&ddb_regs.tf_eax, FCN_NULL, "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL, "edx", (int *)&ddb_regs.tf_edx, FCN_NULL, "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL, "esp", (int *)&ddb_regs.tf_esp,FCN_NULL, "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL, "esi", (int *)&ddb_regs.tf_esi, FCN_NULL, "edi", (int *)&ddb_regs.tf_edi, FCN_NULL, "eip", (int *)&ddb_regs.tf_eip, FCN_NULL, "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); /* * Stack trace. */ #define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS) struct i386_frame { struct i386_frame *f_frame; int f_retaddr; int f_arg0; }; #define TRAP 1 #define INTERRUPT 2 #define SYSCALL 3 db_addr_t db_trap_symbol_value = 0; db_addr_t db_syscall_symbol_value = 0; db_addr_t db_kdintr_symbol_value = 0; boolean_t db_trace_symbols_found = FALSE; void db_find_trace_symbols() { db_expr_t value; if (db_value_of_name("_trap", &value)) db_trap_symbol_value = (db_addr_t) value; if (db_value_of_name("_kdintr", &value)) db_kdintr_symbol_value = (db_addr_t) value; if (db_value_of_name("_syscall", &value)) db_syscall_symbol_value = (db_addr_t) value; db_trace_symbols_found = TRUE; } /* * Figure out how many arguments were passed into the frame at "fp". */ int db_numargs(fp) struct i386_frame *fp; { int *argp; int inst; int args; extern char etext[]; argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE); if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) args = 5; else { inst = db_get_value((int)argp, 4, FALSE); if ((inst & 0xff) == 0x59) /* popl %ecx */ args = 1; else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */ args = ((inst >> 16) & 0xff) / 4; else args = 5; } return (args); } /* * Figure out the next frame up in the call stack. * For trap(), we print the address of the faulting instruction and * proceed with the calling frame. We return the ip that faulted. * If the trap was caused by jumping through a bogus pointer, then * the next line in the backtrace will list some random function as * being called. It should get the argument list correct, though. * It might be possible to dig out from the next frame up the name * of the function that faulted, but that could get hairy. */ void db_nextframe(fp, ip, argp, is_trap) struct i386_frame **fp; /* in/out */ db_addr_t *ip; /* out */ int *argp; /* in */ int is_trap; /* in */ { struct i386_saved_state *saved_regs; switch (is_trap) { case 0: *ip = (db_addr_t) db_get_value((int) &(*fp)->f_retaddr, 4, FALSE); *fp = (struct i386_frame *) db_get_value((int) &(*fp)->f_frame, 4, FALSE); break; case TRAP: default: /* * We know that trap() has 1 argument and we know that * it is an (int *). */ #if 0 saved_regs = (struct i386_saved_state *) db_get_value((int)argp, 4, FALSE); #endif saved_regs = (struct i386_saved_state *)argp; db_printf("--- trap (number %d) ---\n", saved_regs->tf_trapno & 0xffff); db_printsym(saved_regs->tf_eip, DB_STGY_XTRN); db_printf(":\n"); *fp = (struct i386_frame *)saved_regs->tf_ebp; *ip = (db_addr_t)saved_regs->tf_eip; break; case SYSCALL: { struct trapframe *saved_regs = (struct trapframe *)argp; db_printf("--- syscall (number %d) ---\n", saved_regs->tf_eax); db_printsym(saved_regs->tf_eip, DB_STGY_XTRN); db_printf(":\n"); *fp = (struct i386_frame *)saved_regs->tf_ebp; *ip = (db_addr_t)saved_regs->tf_eip; } break; } } void db_stack_trace_cmd(addr, have_addr, count, modif) db_expr_t addr; boolean_t have_addr; db_expr_t count; char *modif; { struct i386_frame *frame, *lastframe; int *argp; db_addr_t callpc; int is_trap; boolean_t kernel_only = TRUE; boolean_t trace_thread = FALSE; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { register char *cp = modif; register char c; while ((c = *cp++) != 0) { if (c == 't') trace_thread = TRUE; if (c == 'u') kernel_only = FALSE; } } if (count == -1) count = 65535; if (!have_addr) { frame = (struct i386_frame *)ddb_regs.tf_ebp; callpc = (db_addr_t)ddb_regs.tf_eip; } else if (trace_thread) { printf ("db_trace.c: can't trace thread\n"); } else { frame = (struct i386_frame *)addr; callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); } lastframe = 0; while (count-- && frame != 0) { int narg; char * name; db_expr_t offset; db_sym_t sym; #define MAXNARG 16 char *argnames[MAXNARG], **argnp = NULL; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (lastframe == 0 && sym == NULL) { /* Symbol not found, peek at code */ int instr = db_get_value(callpc, 4, FALSE); offset = 1; if ((instr & 0x00ffffff) == 0x00e58955 || /* enter: pushl %ebp, movl %esp, %ebp */ (instr & 0x0000ffff) == 0x0000e589 /* enter+1: movl %esp, %ebp */ ) { offset = 0; } } #define STRCMP(s1,s2) ((s1) && (s2) && strcmp((s1), (s2)) == 0) if (INKERNEL((int)frame) && STRCMP(name, "_trap")) { narg = 1; is_trap = TRAP; } else if (INKERNEL((int)frame) && STRCMP(name, "_kdintr")) { is_trap = INTERRUPT; narg = 0; } else if (INKERNEL((int)frame) && STRCMP(name, "_syscall")) { is_trap = SYSCALL; narg = 0; } #undef STRCMP else { is_trap = 0; narg = MAXNARG; if (db_sym_numargs(sym, &narg, argnames)) { argnp = argnames; } else { narg = db_numargs(frame); } } db_printf("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %esp instead */ argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0; } else argp = &frame->f_arg0; while (narg) { if (argnp) db_printf("%s=", *argnp++); db_printf("%x", db_get_value((int)argp, 4, FALSE)); argp++; if (--narg != 0) db_printf(","); } db_printf(") at "); db_printsym(callpc, DB_STGY_PROC); db_printf("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4); callpc = (db_addr_t)db_get_value((int)&lastframe->f_retaddr, 4, FALSE); continue; } lastframe = frame; db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap); if (frame == 0) { /* end of chain */ break; } if (INKERNEL((int)frame)) { /* staying in kernel */ if (frame <= lastframe) { db_printf("Bad frame pointer: 0x%x\n", frame); break; } } else if (INKERNEL((int)lastframe)) { /* switch from user to kernel */ if (kernel_only) break; /* kernel stack only */ } else { /* in user */ if (frame <= lastframe) { db_printf("Bad user frame pointer: 0x%x\n", frame); break; } } } } Index: head/sys/vm/kern_lock.c =================================================================== --- head/sys/vm/kern_lock.c (revision 6805) +++ head/sys/vm/kern_lock.c (revision 6806) @@ -1,535 +1,536 @@ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)kern_lock.c 8.1 (Berkeley) 6/11/93 * * * Copyright (c) 1987, 1990 Carnegie-Mellon University. * All rights reserved. * * Authors: Avadis Tevanian, Jr., Michael Wayne Young * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: kern_lock.c,v 1.2 1994/08/02 07:55:08 davidg Exp $ + * $Id: kern_lock.c,v 1.3 1995/01/09 16:05:30 davidg Exp $ */ /* * Locking primitives implementation */ #include #include -#include - /* XXX */ #include + +#include + typedef int *thread_t; #define current_thread() ((thread_t)&curproc->p_thread) /* XXX */ #if NCPUS > 1 /* * Module: lock * Function: * Provide reader/writer sychronization. * Implementation: * Simple interlock on a bit. Readers first interlock * increment the reader count, then let go. Writers hold * the interlock (thus preventing further readers), and * wait for already-accepted readers to go away. */ /* * The simple-lock routines are the primitives out of which * the lock package is built. The implementation is left * to the machine-dependent code. */ #ifdef notdef /* * A sample implementation of simple locks. * assumes: * boolean_t test_and_set(boolean_t *) * indivisibly sets the boolean to TRUE * and returns its old value * and that setting a boolean to FALSE is indivisible. */ /* * simple_lock_init initializes a simple lock. A simple lock * may only be used for exclusive locks. */ void simple_lock_init(l) simple_lock_t l; { *(boolean_t *) l = FALSE; } void simple_lock(l) simple_lock_t l; { while (test_and_set((boolean_t *) l)) continue; } void simple_unlock(l) simple_lock_t l; { *(boolean_t *) l = FALSE; } boolean_t simple_lock_try(l) simple_lock_t l; { return (!test_and_set((boolean_t *) l)); } #endif /* notdef */ #endif /* NCPUS > 1 */ #if NCPUS > 1 int lock_wait_time = 100; #else /* NCPUS > 1 */ /* * It is silly to spin on a uni-processor as if we thought something magical * would happen to the want_write bit while we are executing. */ int lock_wait_time = 0; #endif /* NCPUS > 1 */ /* * Routine: lock_init * Function: * Initialize a lock; required before use. * Note that clients declare the "struct lock" * variables and then initialize them, rather * than getting a new one from this module. */ void lock_init(l, can_sleep) lock_t l; boolean_t can_sleep; { bzero(l, sizeof(lock_data_t)); simple_lock_init(&l->interlock); l->want_write = FALSE; l->want_upgrade = FALSE; l->read_count = 0; l->can_sleep = can_sleep; l->thread = (char *) -1; /* XXX */ l->recursion_depth = 0; } void lock_sleepable(l, can_sleep) lock_t l; boolean_t can_sleep; { simple_lock(&l->interlock); l->can_sleep = can_sleep; simple_unlock(&l->interlock); } /* * Sleep locks. These use the same data structure and algorithm * as the spin locks, but the process sleeps while it is waiting * for the lock. These work on uniprocessor systems. */ void lock_write(l) register lock_t l; { register int i; simple_lock(&l->interlock); if (((thread_t) l->thread) == current_thread()) { /* * Recursive lock. */ l->recursion_depth++; simple_unlock(&l->interlock); return; } /* * Try to acquire the want_write bit. */ while (l->want_write) { if ((i = lock_wait_time) > 0) { simple_unlock(&l->interlock); while (--i > 0 && l->want_write) continue; simple_lock(&l->interlock); } if (l->can_sleep && l->want_write) { l->waiting = TRUE; thread_sleep((int) l, &l->interlock, FALSE); simple_lock(&l->interlock); } } l->want_write = TRUE; /* Wait for readers (and upgrades) to finish */ while ((l->read_count != 0) || l->want_upgrade) { if ((i = lock_wait_time) > 0) { simple_unlock(&l->interlock); while (--i > 0 && (l->read_count != 0 || l->want_upgrade)) continue; simple_lock(&l->interlock); } if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) { l->waiting = TRUE; thread_sleep((int) l, &l->interlock, FALSE); simple_lock(&l->interlock); } } simple_unlock(&l->interlock); } void lock_done(l) register lock_t l; { simple_lock(&l->interlock); if (l->read_count != 0) l->read_count--; else if (l->recursion_depth != 0) l->recursion_depth--; else if (l->want_upgrade) l->want_upgrade = FALSE; else l->want_write = FALSE; if (l->waiting) { l->waiting = FALSE; thread_wakeup((int) l); } simple_unlock(&l->interlock); } void lock_read(l) register lock_t l; { register int i; simple_lock(&l->interlock); if (((thread_t) l->thread) == current_thread()) { /* * Recursive lock. */ l->read_count++; simple_unlock(&l->interlock); return; } while (l->want_write || l->want_upgrade) { if ((i = lock_wait_time) > 0) { simple_unlock(&l->interlock); while (--i > 0 && (l->want_write || l->want_upgrade)) continue; simple_lock(&l->interlock); } if (l->can_sleep && (l->want_write || l->want_upgrade)) { l->waiting = TRUE; thread_sleep((int) l, &l->interlock, FALSE); simple_lock(&l->interlock); } } l->read_count++; simple_unlock(&l->interlock); } /* * Routine: lock_read_to_write * Function: * Improves a read-only lock to one with * write permission. If another reader has * already requested an upgrade to a write lock, * no lock is held upon return. * * Returns TRUE if the upgrade *failed*. */ boolean_t lock_read_to_write(l) register lock_t l; { register int i; simple_lock(&l->interlock); l->read_count--; if (((thread_t) l->thread) == current_thread()) { /* * Recursive lock. */ l->recursion_depth++; simple_unlock(&l->interlock); return (FALSE); } if (l->want_upgrade) { /* * Someone else has requested upgrade. Since we've released a * read lock, wake him up. */ if (l->waiting) { l->waiting = FALSE; thread_wakeup((int) l); } simple_unlock(&l->interlock); return (TRUE); } l->want_upgrade = TRUE; while (l->read_count != 0) { if ((i = lock_wait_time) > 0) { simple_unlock(&l->interlock); while (--i > 0 && l->read_count != 0) continue; simple_lock(&l->interlock); } if (l->can_sleep && l->read_count != 0) { l->waiting = TRUE; thread_sleep((int) l, &l->interlock, FALSE); simple_lock(&l->interlock); } } simple_unlock(&l->interlock); return (FALSE); } void lock_write_to_read(l) register lock_t l; { simple_lock(&l->interlock); l->read_count++; if (l->recursion_depth != 0) l->recursion_depth--; else if (l->want_upgrade) l->want_upgrade = FALSE; else l->want_write = FALSE; if (l->waiting) { l->waiting = FALSE; thread_wakeup((int) l); } simple_unlock(&l->interlock); } /* * Routine: lock_try_write * Function: * Tries to get a write lock. * * Returns FALSE if the lock is not held on return. */ boolean_t lock_try_write(l) register lock_t l; { simple_lock(&l->interlock); if (((thread_t) l->thread) == current_thread()) { /* * Recursive lock */ l->recursion_depth++; simple_unlock(&l->interlock); return (TRUE); } if (l->want_write || l->want_upgrade || l->read_count) { /* * Can't get lock. */ simple_unlock(&l->interlock); return (FALSE); } /* * Have lock. */ l->want_write = TRUE; simple_unlock(&l->interlock); return (TRUE); } /* * Routine: lock_try_read * Function: * Tries to get a read lock. * * Returns FALSE if the lock is not held on return. */ boolean_t lock_try_read(l) register lock_t l; { simple_lock(&l->interlock); if (((thread_t) l->thread) == current_thread()) { /* * Recursive lock */ l->read_count++; simple_unlock(&l->interlock); return (TRUE); } if (l->want_write || l->want_upgrade) { simple_unlock(&l->interlock); return (FALSE); } l->read_count++; simple_unlock(&l->interlock); return (TRUE); } /* * Routine: lock_try_read_to_write * Function: * Improves a read-only lock to one with * write permission. If another reader has * already requested an upgrade to a write lock, * the read lock is still held upon return. * * Returns FALSE if the upgrade *failed*. */ boolean_t lock_try_read_to_write(l) register lock_t l; { simple_lock(&l->interlock); if (((thread_t) l->thread) == current_thread()) { /* * Recursive lock */ l->read_count--; l->recursion_depth++; simple_unlock(&l->interlock); return (TRUE); } if (l->want_upgrade) { simple_unlock(&l->interlock); return (FALSE); } l->want_upgrade = TRUE; l->read_count--; while (l->read_count != 0) { l->waiting = TRUE; thread_sleep((int) l, &l->interlock, FALSE); simple_lock(&l->interlock); } simple_unlock(&l->interlock); return (TRUE); } /* * Allow a process that has a lock for write to acquire it * recursively (for read, write, or update). */ void lock_set_recursive(l) lock_t l; { simple_lock(&l->interlock); if (!l->want_write) { panic("lock_set_recursive: don't have write lock"); } l->thread = (char *) current_thread(); simple_unlock(&l->interlock); } /* * Prevent a lock from being re-acquired. */ void lock_clear_recursive(l) lock_t l; { simple_lock(&l->interlock); if (((thread_t) l->thread) != current_thread()) { panic("lock_clear_recursive: wrong thread"); } if (l->recursion_depth == 0) l->thread = (char *) -1; /* XXX */ simple_unlock(&l->interlock); }