Initial fix of upstream merge.

This commit is contained in:
Geoffrey Challen
2017-02-09 10:09:30 -05:00
42 changed files with 828 additions and 74 deletions

View File

@@ -69,8 +69,6 @@ struct trapframe {
uint32_t tf_s7;
uint32_t tf_t8;
uint32_t tf_t9;
uint32_t tf_k0; /* dummy (see exception-mips1.S comments) */
uint32_t tf_k1; /* dummy */
uint32_t tf_gp;
uint32_t tf_sp;
uint32_t tf_s8;

View File

@@ -101,6 +101,8 @@ mips_general_end:
.text
.type common_exception,@function
.ent common_exception
.cfi_startproc
.cfi_signal_frame
common_exception:
mfc0 k0, c0_status /* Get status register */
andi k0, k0, CST_KUp /* Check the we-were-in-user-mode bit */
@@ -130,11 +132,12 @@ common_exception:
*/
/*
* Allocate stack space for 37 words to hold the trap frame,
* Allocate stack space for 35 words to hold the trap frame,
* plus four more words for a minimal argument block, plus
* one more for proper (64-bit) stack alignment.
*/
addi sp, sp, -168
addi sp, sp, -160
.cfi_def_cfa sp, 0
/*
* Save general registers.
@@ -143,70 +146,89 @@ common_exception:
*
* The order here must match mips/include/trapframe.h.
*
* gdb disassembles this code to try to figure out what registers
* are where, and it isn't very bright. So in order to make gdb be
* able to trace the stack back through here, we play some silly
* games.
* gdb uses the .cfi_offset assembler directives inserted below to
* to figure out where each register is stored. Since we've marked
* this function as a "signal handler" with the .cfi_signal_frame
* directive, gdb won't complain about the fact that the stack
* is noncontiguous (if we're coming from userland).
*
* In particular:
* (1) We store the return address register into the epc slot,
* which makes gdb think it's the return address slot. Then
* we store the real epc value over that.
* (2) We store the current sp into the sp slot, which makes gdb
* think it's the stack pointer slot. Then we store the real
* value.
* (3) gdb also assumes that saved registers in a function are
* saved in order. This is why we put epc where it is, and
* handle the real value of ra afterwards.
* (4) Because gdb will think we're saving k0 and k1, we need to
* leave slots for them in the trap frame, even though the
* stuff we save there is useless.
* We also play a trick with the return address: we mark the ra
* register as stored to the stack normally and then mark the
* return address for *this* function as being in the k1 register
* using the .cfi_return_column directive. gdb is then able to
* recognize that the ra we've stored here is the return address
* for the function that was executing when this exception was
* taken.
*
* This logic has not been tested against a recent gdb and has
* probably bitrotted. Someone(TM) should figure out what gdb
* currently expects -- or maybe even patch gdb to understand a
* better form of this that doesn't waste so many cycles.
* All of the cfi (call frame information) material is compiled
* into the .eh_frame section of the compiled kernel.
*/
sw ra, 160(sp) /* dummy for gdb */
sw s8, 156(sp) /* save s8 */
sw sp, 152(sp) /* dummy for gdb */
sw gp, 148(sp) /* save gp */
sw k1, 144(sp) /* dummy for gdb */
sw k0, 140(sp) /* dummy for gdb */
sw k1, 152(sp) /* real saved sp */
sw s8, 148(sp) /* save s8 */
.cfi_offset s8, 148
sw k1, 144(sp) /* real saved sp */
.cfi_offset sp, 144
sw gp, 140(sp) /* save gp */
nop /* delay slot for store */
.cfi_offset gp, 140
.cfi_return_column k1
mfc0 k1, c0_epc /* Copr.0 reg 13 == PC for exception */
sw k1, 160(sp) /* real saved PC */
sw k1, 152(sp) /* real saved PC */
.cfi_offset k1, 152
sw t9, 136(sp)
.cfi_offset t9, 136
sw t8, 132(sp)
.cfi_offset t8, 132
sw s7, 128(sp)
.cfi_offset s7, 128
sw s6, 124(sp)
.cfi_offset s6, 124
sw s5, 120(sp)
.cfi_offset s5, 120
sw s4, 116(sp)
.cfi_offset s4, 116
sw s3, 112(sp)
.cfi_offset s3, 112
sw s2, 108(sp)
.cfi_offset s2, 108
sw s1, 104(sp)
.cfi_offset s1, 104
sw s0, 100(sp)
.cfi_offset s0, 100
sw t7, 96(sp)
.cfi_offset t7, 96
sw t6, 92(sp)
.cfi_offset t6, 92
sw t5, 88(sp)
.cfi_offset t5, 88
sw t4, 84(sp)
.cfi_offset t4, 84
sw t3, 80(sp)
.cfi_offset t3, 80
sw t2, 76(sp)
.cfi_offset t2, 76
sw t1, 72(sp)
.cfi_offset t1, 72
sw t0, 68(sp)
.cfi_offset t0, 68
sw a3, 64(sp)
.cfi_offset a3, 64
sw a2, 60(sp)
.cfi_offset a2, 60
sw a1, 56(sp)
.cfi_offset a1, 56
sw a0, 52(sp)
.cfi_offset a0, 52
sw v1, 48(sp)
.cfi_offset v1, 48
sw v0, 44(sp)
.cfi_offset v0, 44
sw AT, 40(sp)
.cfi_offset AT, 40
sw ra, 36(sp)
.cfi_offset ra, 36
/*
* Save special registers.
@@ -227,11 +249,6 @@ common_exception:
mfc0 t4, c0_cause
sw t4, 24(sp) /* Copr.0 reg 13 == exception cause */
/*
* Pretend to save $0 for gdb's benefit.
*/
sw $0, 12(sp)
/*
* Load the curthread register if coming from user mode.
*/
@@ -260,9 +277,6 @@ common_exception:
jal mips_trap /* call it */
nop /* delay slot */
/* Something must be here or gdb doesn't find the stack frame. */
nop
/*
* Now restore stuff and return from the exception.
* Interrupts should be off.
@@ -309,20 +323,17 @@ exception_return:
lw s7, 128(sp)
lw t8, 132(sp)
lw t9, 136(sp)
lw gp, 140(sp) /* restore gp */
/* 144(sp) stack pointer - below */
lw s8, 148(sp) /* restore s8 */
lw k1, 152(sp) /* fetch exception return PC into k1 */
/* 140(sp) "saved" k0 was dummy garbage anyway */
/* 144(sp) "saved" k1 was dummy garbage anyway */
lw gp, 148(sp) /* restore gp */
/* 152(sp) stack pointer - below */
lw s8, 156(sp) /* restore s8 */
lw k0, 160(sp) /* fetch exception return PC into k0 */
lw sp, 152(sp) /* fetch saved sp (must be last) */
lw sp, 144(sp) /* fetch saved sp (must be last) */
/* done */
jr k0 /* jump back */
jr k1 /* jump back */
rfe /* in delay slot */
.cfi_endproc
.end common_exception
/*

View File

@@ -130,8 +130,8 @@ mips_trap(struct trapframe *tf)
bool iskern;
int spl;
/* The trap frame is supposed to be 37 registers long. */
KASSERT(sizeof(struct trapframe)==(37*4));
/* The trap frame is supposed to be 35 registers long. */
KASSERT(sizeof(struct trapframe)==(35*4));
/*
* Extract the exception code info from the register fields.

View File

@@ -54,6 +54,14 @@
*
* These arrays are also used to start up new CPUs, for roughly the
* same reasons.
*
* The values in the current cpu's slots in these arrays are updated
* with the current thread's information in trap.c before heading to
* userlevel, as well as being initialized in cpu_machdep_init below.
* This means that (unless something really horrible happens) on entry
* to the kernel, and when a new CPU starts up in cpu_start_secondary,
* they will have the information needed to figure out who we are and
* proceed.
*/
vaddr_t cpustacks[MAXCPUS];

View File

@@ -42,6 +42,7 @@
#include <mainbus.h>
#include <sys161/bus.h>
#include <lamebus/lamebus.h>
#include <lamebus/ltrace.h>
#include "autoconf.h"
/*
@@ -275,6 +276,15 @@ mainbus_send_ipi(struct cpu *target)
lamebus_assert_ipi(lamebus, target);
}
/*
* Trigger the debugger.
*/
void
mainbus_debugger(void)
{
ltrace_stop(0);
}
/*
* Interrupt dispatcher.
*/

View File

@@ -3,7 +3,9 @@
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
debug # Compile with debug info and -Og.
#debugonly # Compile with debug info only (no -Og).
options hangman # Deadlock detection. (off by default)
#
# Device drivers for hardware.

View File

@@ -7,6 +7,7 @@
include conf/conf.kern # get definitions of available options
#debug # Optimizing compile (no debug).
#debugonly
options noasserts # Disable assertions.
#

View File

@@ -5,6 +5,8 @@
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
#debugonly # Compile with debug info only (no -Og).
#options hangman # Deadlock detection. (off by default)
#
# Device drivers for hardware.

View File

@@ -7,6 +7,7 @@
include conf/conf.kern # get definitions of available options
#debug # Optimizing compile (no debug).
#debugonly
options noasserts # Disable assertions.
#

View File

@@ -334,6 +334,9 @@ file thread/synch.c
file thread/thread.c
file thread/threadlist.c
defoption hangman
optfile hangman thread/hangman.c
#
# Process system
#

View File

@@ -12,7 +12,8 @@
# Recognized directives:
#
# file <filename> use source file
# debug turn on debug info
# debug turn on debug info and -Og
# debugonly turn on debug info without -Og
# defoption <sym> define an option
# optfile <sym> <file> if option <sym> is enabled, use file <file>
# optofffile <sym> <file> if option <sym> is disabled, use file <file>
@@ -97,6 +98,7 @@ echo "$CONFNAME" $CONFTMP | awk '
nfields["include"] = 2;
nfields["file"] = 2;
nfields["debug"] = 1;
nfields["debugonly"] = 1;
nfields["defoption"] = 2;
nfields["optfile"] = 3;
nfields["optofffile"] = 3;
@@ -776,6 +778,9 @@ echo -n ' files.mk'
# Default: optimize.
BEGIN { debugflags="-O2"; }
$1=="debug" {
debugflags="-g -Og";
}
$1=="debugonly" {
debugflags="-g";
}

View File

@@ -0,0 +1,40 @@
# commands to interact with userland
define load-userprogram
init-if-undefined $userprog_loaded = 0
if !$userprog_loaded || !$_streq($arg0, $cur_userprog)
add-symbol-file $arg0 0x4000b0
# remove after adding the new file in case add-symbol-file fails
if $userprog_loaded
remove-symbol-file -a 0x4000b0
end
set $userprog_loaded = 1
set $cur_userprog = $arg0
end
end
document load-userprogram
Loads a single user program into gdb's symbol table, removing
the previous user program loaded if one exists.
Usage: load-userprogram <path-to-prog>
end
alias -a lu = load-userprogram
define auto-userprogram
set $pname = curthread->t_proc->p_name
if $pname != 0 && $pname[0] != 0 && !$_streq($pname, "[kernel]")
if $pname[0] == '/'
set $pname = $pname + 1
end
# This dumbness works around the fact that gdb doesn't
# expand convenience variables when you execute commands.
# And setting the third parameter to True silences the command.
python gdb.execute("load-userprogram " + str(gdb.parse_and_eval("$pname")).split()[1], False, True)
end
end
document auto-userprogram
Calls load-userprogram on whatever is curproc->p_name. It is meant
to work with kernels that set p_name to an absolute path to the
program, and it is designed to be called from hook-stop.
Usage: auto-userprogram
end

View File

@@ -88,6 +88,11 @@ struct cpu {
struct tlbshootdown c_shootdown[TLBSHOOTDOWN_MAX];
unsigned c_numshootdown;
struct spinlock c_ipi_lock;
/*
* Accessed by other cpus. Protected inside hangman.c.
*/
HANGMAN_ACTOR(c_hangman);
};
/*

84
kern/include/hangman.h Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2015
* The President and Fellows of Harvard College.
*
* 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. 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 UNIVERSITY 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 UNIVERSITY 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.
*/
#ifndef HANGMAN_H
#define HANGMAN_H
/*
* Simple deadlock detector. Enable with "options hangman" in the
* kernel config.
*/
#include "opt-hangman.h"
#if OPT_HANGMAN
struct hangman_actor {
const char *a_name;
const struct hangman_lockable *a_waiting;
};
struct hangman_lockable {
const char *l_name;
const struct hangman_actor *l_holding;
};
void hangman_wait(struct hangman_actor *a, struct hangman_lockable *l);
void hangman_acquire(struct hangman_actor *a, struct hangman_lockable *l);
void hangman_release(struct hangman_actor *a, struct hangman_lockable *l);
#define HANGMAN_ACTOR(sym) struct hangman_actor sym
#define HANGMAN_LOCKABLE(sym) struct hangman_lockable sym
#define HANGMAN_ACTORINIT(a, n) ((a)->a_name = (n), (a)->a_waiting = NULL)
#define HANGMAN_LOCKABLEINIT(l, n) ((l)->l_name = (n), (l)->l_holding = NULL)
#define HANGMAN_LOCKABLE_INITIALIZER { "spinlock", NULL }
#define HANGMAN_WAIT(a, l) hangman_wait(a, l)
#define HANGMAN_ACQUIRE(a, l) hangman_acquire(a, l)
#define HANGMAN_RELEASE(a, l) hangman_release(a, l)
#else
#define HANGMAN_ACTOR(sym)
#define HANGMAN_LOCKABLE(sym)
#define HANGMAN_ACTORINIT(a, name)
#define HANGMAN_LOCKABLEINIT(a, name)
#define HANGMAN_LOCKABLE_INITIALIZER
#define HANGMAN_WAIT(a, l)
#define HANGMAN_ACQUIRE(a, l)
#define HANGMAN_RELEASE(a, l)
#endif
#endif /* HANGMAN_H */

View File

@@ -194,7 +194,7 @@ void kprintf_bootstrap(void);
*/
#define DIVROUNDUP(a,b) (((a)+(b)-1)/(b))
#define ROUNDUP(a,b) (DIVROUNDUP(a,b)*b)
#define ROUNDUP(a,b) (DIVROUNDUP(a,b)*(b))
#endif /* _LIB_H_ */

View File

@@ -55,6 +55,9 @@ size_t mainbus_ramsize(void);
/* Switch on an inter-processor interrupt. (Low-level.) */
void mainbus_send_ipi(struct cpu *target);
/* Request breaking into the debugger, where available. */
void mainbus_debugger(void);
/*
* The various ways to shut down the system. (These are very low-level
* and should generally not be called directly - md_poweroff, for

View File

@@ -36,6 +36,7 @@
*/
#include <cdefs.h>
#include <hangman.h>
/* Inlining support - for making sure an out-of-line copy gets built */
#ifndef SPINLOCK_INLINE
@@ -57,12 +58,18 @@
struct spinlock {
volatile spinlock_data_t splk_lock; /* Memory word where we spin. */
struct cpu *splk_holder; /* CPU holding this lock. */
HANGMAN_LOCKABLE(splk_hangman); /* Deadlock detector hook. */
};
/*
* Initializer for cases where a spinlock needs to be static or global.
*/
#ifdef OPT_HANGMAN
#define SPINLOCK_INITIALIZER { SPINLOCK_DATA_INITIALIZER, NULL, \
HANGMAN_LOCKABLE_INITIALIZER }
#else
#define SPINLOCK_INITIALIZER { SPINLOCK_DATA_INITIALIZER, NULL }
#endif
/*
* Spinlock functions.

View File

@@ -74,6 +74,7 @@ void V(struct semaphore *);
*/
struct lock {
char *lk_name;
HANGMAN_LOCKABLE(lk_hangman); /* Deadlock detector hook. */
// add what you need here
// (don't forget to mark things volatile as needed)
};

View File

@@ -93,6 +93,7 @@ struct thread {
struct switchframe *t_context; /* Saved register context (on stack) */
struct cpu *t_cpu; /* CPU thread runs on */
struct proc *t_proc; /* Process thread belongs to */
HANGMAN_ACTOR(t_hangman); /* Deadlock detector hook */
/*
* Interrupt state fields.

View File

@@ -34,7 +34,7 @@
* Leave this alone, so we can tell what version of the OS/161 base
* code we gave you.
*/
#define BASE_VERSION "2.0.2"
#define BASE_VERSION "2.0.3"
/*
* Change this as you see fit in the course of hacking the system.

View File

@@ -35,6 +35,8 @@
#include <lib.h>
#include <uio.h>
#include <clock.h>
#include <mainbus.h>
#include <synch.h>
#include <thread.h>
#include <proc.h>
#include <vfs.h>
@@ -247,6 +249,21 @@ cmd_sync(int nargs, char **args)
return 0;
}
/*
* Command for dropping to the debugger.
*/
static
int
cmd_debug(int nargs, char **args)
{
(void)nargs;
(void)args;
mainbus_debugger();
return 0;
}
/*
* Command for doing an intentional panic.
*/
@@ -261,6 +278,81 @@ cmd_panic(int nargs, char **args)
return 0;
}
/*
* Subthread for intentially deadlocking.
*/
struct deadlock {
struct lock *lock1;
struct lock *lock2;
};
static
void
cmd_deadlockthread(void *ptr, unsigned long num)
{
struct deadlock *dl = ptr;
(void)num;
/* If it doesn't wedge right away, keep trying... */
while (1) {
lock_acquire(dl->lock2);
lock_acquire(dl->lock1);
kprintf("+");
lock_release(dl->lock1);
lock_release(dl->lock2);
}
}
/*
* Command for doing an intentional deadlock.
*/
static
int
cmd_deadlock(int nargs, char **args)
{
struct deadlock dl;
int result;
(void)nargs;
(void)args;
dl.lock1 = lock_create("deadlock1");
if (dl.lock1 == NULL) {
kprintf("lock_create failed\n");
return ENOMEM;
}
dl.lock2 = lock_create("deadlock2");
if (dl.lock2 == NULL) {
lock_destroy(dl.lock1);
kprintf("lock_create failed\n");
return ENOMEM;
}
result = thread_fork(args[0] /* thread name */,
NULL /* kernel thread */,
cmd_deadlockthread /* thread function */,
&dl /* thread arg */, 0 /* thread arg */);
if (result) {
kprintf("thread_fork failed: %s\n", strerror(result));
lock_release(dl.lock1);
lock_destroy(dl.lock2);
lock_destroy(dl.lock1);
return result;
}
/* If it doesn't wedge right away, keep trying... */
while (1) {
lock_acquire(dl.lock1);
lock_acquire(dl.lock2);
kprintf(".");
lock_release(dl.lock2);
lock_release(dl.lock1);
}
/* NOTREACHED */
return 0;
}
/*
* Command for shutting down.
*/
@@ -463,7 +555,9 @@ static const char *opsmenu[] = {
"[cd] Change directory ",
"[pwd] Print current directory ",
"[sync] Sync filesystems ",
"[debug] Drop to debugger ",
"[panic] Intentional panic ",
"[deadlock] Intentional deadlock ",
"[q] Quit and shut down ",
NULL
};
@@ -614,7 +708,9 @@ static struct {
{ "cd", cmd_chdir },
{ "pwd", cmd_pwd },
{ "sync", cmd_sync },
{ "debug", cmd_debug },
{ "panic", cmd_panic },
{ "deadlock", cmd_deadlock },
{ "q", cmd_quit },
{ "exit", cmd_quit },
{ "halt", cmd_quit },

View File

@@ -156,6 +156,9 @@ arraytest2(int nargs, char **args)
(void)nargs;
(void)args;
/* Silence warning with gcc 4.8 -Og (but not -O2) */
x = 0;
kprintf("Beginning large array test...\n");
a = array_create();
KASSERT(a != NULL);

View File

@@ -681,7 +681,7 @@ checkfilesystem(int nargs, char **args)
char *device;
if (nargs != 2) {
kprintf("Usage: fs[12345] filesystem:\n");
kprintf("Usage: fs[123456] filesystem:\n");
return EINVAL;
}

182
kern/thread/hangman.c Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2015
* The President and Fellows of Harvard College.
*
* 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. 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 UNIVERSITY 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 UNIVERSITY 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.
*/
/*
* Simple deadlock detector.
*/
#include <types.h>
#include <lib.h>
#include <spl.h>
#include <spinlock.h>
#include <hangman.h>
static struct spinlock hangman_lock = SPINLOCK_INITIALIZER;
/*
* Look for a path through the waits-for graph that goes from START to
* TARGET.
*
* Because lockables can only be held by one actor, and actors can
* only be waiting for one thing at a time, this turns out to be
* quite simple.
*/
static
void
hangman_check(const struct hangman_lockable *start,
const struct hangman_actor *target)
{
const struct hangman_actor *cur;
cur = start->l_holding;
while (cur != NULL) {
if (cur == target) {
goto found;
}
if (cur->a_waiting == NULL) {
break;
}
cur = cur->a_waiting->l_holding;
}
return;
found:
/*
* None of this can change while we print it (that's the point
* of it being a deadlock) so drop hangman_lock while
* printing; otherwise we can come back via kprintf_spinlock
* and that makes a mess. But force splhigh() explicitly so
* the console prints in polled mode and to discourage other
* things from running in the middle of the printout.
*/
splhigh();
spinlock_release(&hangman_lock);
kprintf("hangman: Detected lock cycle!\n");
kprintf("hangman: in %s (%p);\n", target->a_name, target);
kprintf("hangman: waiting for %s (%p), but:\n", start->l_name, start);
kprintf(" lockable %s (%p)\n", start->l_name, start);
cur = start->l_holding;
while (cur != target) {
kprintf(" held by actor %s (%p)\n", cur->a_name, cur);
kprintf(" waiting for lockable %s (%p)\n",
cur->a_waiting->l_name, cur->a_waiting);
cur = cur->a_waiting->l_holding;
}
kprintf(" held by actor %s (%p)\n", cur->a_name, cur);
panic("Deadlock.\n");
}
/*
* Note that a is about to wait for l.
*
* Note that there's no point calling this if a isn't going to wait,
* because in that case l->l_holding will be null and the check
* won't go anywhere.
*
* One could also maintain in memory a graph of all requests ever
* seen, in order to detect lock order inversions that haven't
* actually deadlocked; but there are a lot of ways in which this is
* tricky and problematic. For now we'll settle for just detecting and
* reporting deadlocks that do happen.
*/
void
hangman_wait(struct hangman_actor *a,
struct hangman_lockable *l)
{
if (l == &hangman_lock.splk_hangman) {
/* don't recurse */
return;
}
spinlock_acquire(&hangman_lock);
if (a->a_waiting != NULL) {
spinlock_release(&hangman_lock);
panic("hangman_wait: already waiting for something?\n");
}
hangman_check(l, a);
a->a_waiting = l;
spinlock_release(&hangman_lock);
}
void
hangman_acquire(struct hangman_actor *a,
struct hangman_lockable *l)
{
if (l == &hangman_lock.splk_hangman) {
/* don't recurse */
return;
}
spinlock_acquire(&hangman_lock);
if (a->a_waiting != l) {
spinlock_release(&hangman_lock);
panic("hangman_acquire: not waiting for lock %s (%p)\n",
l->l_name, l);
}
if (l->l_holding != NULL) {
spinlock_release(&hangman_lock);
panic("hangman_acquire: lock %s (%p) still held by %s (%p)\n",
l->l_name, l, a->a_name, a);
}
l->l_holding = a;
a->a_waiting = NULL;
spinlock_release(&hangman_lock);
}
void
hangman_release(struct hangman_actor *a,
struct hangman_lockable *l)
{
if (l == &hangman_lock.splk_hangman) {
/* don't recurse */
return;
}
spinlock_acquire(&hangman_lock);
if (a->a_waiting != NULL) {
spinlock_release(&hangman_lock);
panic("hangman_release: waiting for something?\n");
}
if (l->l_holding != a) {
spinlock_release(&hangman_lock);
panic("hangman_release: not the holder\n");
}
l->l_holding = NULL;
spinlock_release(&hangman_lock);
}

View File

@@ -52,6 +52,7 @@ spinlock_init(struct spinlock *splk)
{
spinlock_data_set(&splk->splk_lock, 0);
splk->splk_holder = NULL;
HANGMAN_LOCKABLEINIT(&splk->splk_hangman, "spinlock");
}
/*
@@ -85,6 +86,8 @@ spinlock_acquire(struct spinlock *splk)
panic("Deadlock on spinlock %p\n", splk);
}
mycpu->c_spinlocks++;
HANGMAN_WAIT(&curcpu->c_hangman, &splk->splk_hangman);
}
else {
mycpu = NULL;
@@ -112,6 +115,10 @@ spinlock_acquire(struct spinlock *splk)
membar_store_any();
splk->splk_holder = mycpu;
if (CURCPU_EXISTS()) {
HANGMAN_ACQUIRE(&curcpu->c_hangman, &splk->splk_hangman);
}
}
/*
@@ -125,6 +132,7 @@ spinlock_release(struct spinlock *splk)
KASSERT(splk->splk_holder == curcpu->c_self);
KASSERT(curcpu->c_spinlocks > 0);
curcpu->c_spinlocks--;
HANGMAN_RELEASE(&curcpu->c_hangman, &splk->splk_hangman);
}
splk->splk_holder = NULL;

View File

@@ -154,6 +154,8 @@ lock_create(const char *name)
return NULL;
}
HANGMAN_LOCKABLEINIT(&lock->lk_hangman, lock->lk_name);
// add stuff here as needed
return lock;
@@ -173,14 +175,23 @@ lock_destroy(struct lock *lock)
void
lock_acquire(struct lock *lock)
{
/* Call this (atomically) before waiting for a lock */
//HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
// Write this
(void)lock; // suppress warning until code gets written
/* Call this (atomically) once the lock is acquired */
//HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman);
}
void
lock_release(struct lock *lock)
{
/* Call this (atomically) when the lock is released */
//HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman);
// Write this
(void)lock; // suppress warning until code gets written

View File

@@ -145,6 +145,7 @@ thread_create(const char *name)
thread->t_context = NULL;
thread->t_cpu = NULL;
thread->t_proc = NULL;
HANGMAN_ACTORINIT(&thread->t_hangman, thread->t_name);
/* Interrupt state fields */
thread->t_in_interrupt = false;
@@ -244,6 +245,8 @@ cpu_create(unsigned hardware_number)
curcpu->c_curthread = curthread;
}
HANGMAN_ACTORINIT(&c->c_hangman, "cpu");
result = proc_addthread(kproc, c->c_curthread);
if (result) {
panic("cpu_create: proc_addthread:: %s\n", strerror(result));

View File

@@ -129,6 +129,23 @@ vfs_biglock_acquire(void)
if (!lock_do_i_hold(vfs_biglock)) {
lock_acquire(vfs_biglock);
}
else if (vfs_biglock_depth == 0) {
/*
* Supposedly we hold it, but the depth is 0. This may
* mean: (1) the count is messed up, or (2)
* lock_do_i_hold is lying. Since OS/161 ships out of
* the box with unimplemented locks (students
* implement them) that always return true, assume
* situation (2). In this case acquire the lock
* anyway.
*
* Once you have working locks, this won't be the
* case, and if you get here it should be situation
* (1), in which case the count is messed up and one
* can panic.
*/
lock_acquire(vfs_biglock);
}
vfs_biglock_depth++;
}
@@ -381,6 +398,9 @@ vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs)
unsigned index;
int result;
/* Silence warning with gcc 4.8 -Og (but not -O2) */
index = 0;
vfs_biglock_acquire();
name = kstrdup(dname);

View File

@@ -135,6 +135,13 @@ getdevice(char *path, char **subpath, struct vnode **startvn)
KASSERT(vfs_biglock_do_i_hold());
/*
* Entirely empty filenames aren't legal.
*/
if (path[0] == 0) {
return EINVAL;
}
/*
* Locate the first colon or slash.
*/

View File

@@ -1113,6 +1113,10 @@ subpage_kfree(void *ptr)
checksubpages();
/* Silence warnings with gcc 4.8 -Og (but not -O2) */
prpage = 0;
blktype = 0;
for (pr = allbase; pr; pr = pr->next_all) {
prpage = PR_PAGEADDR(pr);
blktype = PR_BLOCKTYPE(pr);