Initial fix of upstream merge.
This commit is contained in:
		
							
								
								
									
										98
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								CHANGES
									
									
									
									
									
								
							@@ -12,6 +12,96 @@ various other people, all of whom are (hopefully) listed below.
 | 
				
			|||||||
------------------------------------------------------------
 | 
					------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OS/161 2.0.3 released 20160124
 | 
				
			||||||
 | 
					------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170124 dholland in base
 | 
				
			||||||
 | 
					   - Remove obsolete, redundant, or not useful test programs:
 | 
				
			||||||
 | 
						guzzle (same as hog)
 | 
				
			||||||
 | 
						kitchen (equivalent to multiexec -n 4 sink)
 | 
				
			||||||
 | 
						sink (same as conman)
 | 
				
			||||||
 | 
						sty (equivalent to multiexec -n 6 hog)
 | 
				
			||||||
 | 
						quinthuge (offers little over triplehuge, can be done with multiexec)
 | 
				
			||||||
 | 
						quintmat, quintsort (ditto)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170118 dholland in base
 | 
				
			||||||
 | 
					   - Make -g -Og the flags when "debug" is enabled in a kernel config
 | 
				
			||||||
 | 
					     (which it is in the non-OPT ones) and add an additional kernel
 | 
				
			||||||
 | 
					     config verb "debugonly" to get just -g in case that becomes
 | 
				
			||||||
 | 
					     necessary. This should significantly improve the output code
 | 
				
			||||||
 | 
					     quality from gcc without compromising debugging. (However, gcc
 | 
				
			||||||
 | 
					     being gcc, it also sometimes leads to additional spurious
 | 
				
			||||||
 | 
					     warnings that don't occur with either -g or -O2.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170118 dholland in base
 | 
				
			||||||
 | 
					   - Add a MI mainbus_debugger() function that goes through the right
 | 
				
			||||||
 | 
					     MD paths to trigger the debugger hook in the ltrace device. Also
 | 
				
			||||||
 | 
					     add a menu function "debug" to trigger it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170118 dholland in base
 | 
				
			||||||
 | 
					   - Add some bits to forktest to try to catch the case where the fork
 | 
				
			||||||
 | 
					     child returns from the next system call instead of from fork.
 | 
				
			||||||
 | 
					     (Which is a moderately common bug, caused by races copying the
 | 
				
			||||||
 | 
					     trapframe information in the kernel.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base
 | 
				
			||||||
 | 
					   - Add a menu command "deadlock" to intentionally deadlock.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base, from Sam Fishman
 | 
				
			||||||
 | 
					   - Fix parallelvm -w so that if one of the forks fails the whole
 | 
				
			||||||
 | 
					     thing doesn't wedge.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base, reported by Sam Fishman
 | 
				
			||||||
 | 
					   - Don't do semfs I/O from NULL, or from/to insufficiently sized
 | 
				
			||||||
 | 
					     buffers. Like the 20150615 change, except covering the rest of
 | 
				
			||||||
 | 
					     the tests that use the semaphores that were doing it wrong:
 | 
				
			||||||
 | 
					     multiexec, parallelvm, and schedpong.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base, from Sam Fishman
 | 
				
			||||||
 | 
					   - Add assembler directives to exception-mips1.S that tell gdb how
 | 
				
			||||||
 | 
					     to read trap frames correctly. Garbage-collect old stuff left
 | 
				
			||||||
 | 
					     over from making it work with a (much) older version of gdb a
 | 
				
			||||||
 | 
					     long time back. This also usually makes it possible to trace back
 | 
				
			||||||
 | 
					     through a syscall into a userlevel process; include a gdb script
 | 
				
			||||||
 | 
					     with tools for making this useful.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base
 | 
				
			||||||
 | 
					   - Merge the deadlock detector into base. It was a success last year.
 | 
				
			||||||
 | 
					   - Mention in the comments that the hangman hooks in locks need to
 | 
				
			||||||
 | 
					     be called atomically.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base, reported by Jeffrey Cai, patch from Sam Fishman
 | 
				
			||||||
 | 
					   - Fix off-by-one in tac that makes it skip the first line of files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170117 dholland in base, from Sam Fishman
 | 
				
			||||||
 | 
					   - Make badcall's "pipe with unaligned pointer" test clean up after
 | 
				
			||||||
 | 
					     itself if the operation succeeds. Otherwise it leaks fds and that
 | 
				
			||||||
 | 
					     can intefere with other tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170116 dholland in base, reported by Sam Fishman
 | 
				
			||||||
 | 
					   - Don't allow opening an entirely empty pathname to succeed, and
 | 
				
			||||||
 | 
					     don't allow success for this case in badcall either.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20170116 dholland in base, from Sasha Fedorova
 | 
				
			||||||
 | 
					   - Fix write buffer size in filetest.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20160325 dholland in base
 | 
				
			||||||
 | 
					   - Fix macro parenthesis bug in ROUNDUP().
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20160304 dholland in base, from Sam Fishman
 | 
				
			||||||
 | 
					   - Make runtest.py handle spacing in the command strings it's given.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20160216 dholland in base
 | 
				
			||||||
 | 
					   - Fix spacing problems in ls -l output for large files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20160203 dholland in base
 | 
				
			||||||
 | 
					   - Expand comments attached to cpustacks[]/cputhreads[], prompted by
 | 
				
			||||||
 | 
					     James Mickens.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20160125 dholland in base, from Nikhil Benesch.
 | 
				
			||||||
 | 
					   - Fix stupid argument handling bug in test.py.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OS/161 2.0.2 released 20160112
 | 
					OS/161 2.0.2 released 20160112
 | 
				
			||||||
------------------------------
 | 
					------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,6 +143,14 @@ OS/161 2.0.2 released 20160112
 | 
				
			|||||||
     anyway. If they aren't actually constant because of bugs, reading
 | 
					     anyway. If they aren't actually constant because of bugs, reading
 | 
				
			||||||
     a stale or even garbage value is not going to hurt more.
 | 
					     a stale or even garbage value is not going to hurt more.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					20160107 dholland in deadlock-detector
 | 
				
			||||||
 | 
					   - Add a deadlock detector. For now this will be supplied to
 | 
				
			||||||
 | 
					     instructors as a supplementary patch, because it intrudes into
 | 
				
			||||||
 | 
					     the synchronization primitives and affects what students do
 | 
				
			||||||
 | 
					     there. We are planning to try it on our students this coming
 | 
				
			||||||
 | 
					     semester; if that works out well, I'll probably merge it into
 | 
				
			||||||
 | 
					     base.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
20160107 dholland in base
 | 
					20160107 dholland in base
 | 
				
			||||||
   - In testbin/multiexec, if fork fails partway through, continue
 | 
					   - In testbin/multiexec, if fork fails partway through, continue
 | 
				
			||||||
     with the forks we got. Otherwise the subprocesses we started hang
 | 
					     with the forks we got. Otherwise the subprocesses we started hang
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,8 +69,6 @@ struct trapframe {
 | 
				
			|||||||
	uint32_t tf_s7;
 | 
						uint32_t tf_s7;
 | 
				
			||||||
	uint32_t tf_t8;
 | 
						uint32_t tf_t8;
 | 
				
			||||||
	uint32_t tf_t9;
 | 
						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_gp;
 | 
				
			||||||
	uint32_t tf_sp;
 | 
						uint32_t tf_sp;
 | 
				
			||||||
	uint32_t tf_s8;
 | 
						uint32_t tf_s8;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,6 +101,8 @@ mips_general_end:
 | 
				
			|||||||
   .text
 | 
					   .text
 | 
				
			||||||
   .type common_exception,@function
 | 
					   .type common_exception,@function
 | 
				
			||||||
   .ent common_exception
 | 
					   .ent common_exception
 | 
				
			||||||
 | 
					   .cfi_startproc
 | 
				
			||||||
 | 
					   .cfi_signal_frame
 | 
				
			||||||
common_exception:
 | 
					common_exception:
 | 
				
			||||||
   mfc0 k0, c0_status		/* Get status register */
 | 
					   mfc0 k0, c0_status		/* Get status register */
 | 
				
			||||||
   andi k0, k0, CST_KUp		/* Check the we-were-in-user-mode bit */
 | 
					   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
 | 
					    * plus four more words for a minimal argument block, plus
 | 
				
			||||||
    * one more for proper (64-bit) stack alignment.
 | 
					    * one more for proper (64-bit) stack alignment.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
   addi sp, sp, -168
 | 
					   addi sp, sp, -160
 | 
				
			||||||
 | 
					   .cfi_def_cfa sp, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /*
 | 
					   /*
 | 
				
			||||||
    * Save general registers.
 | 
					    * Save general registers.
 | 
				
			||||||
@@ -143,70 +146,89 @@ common_exception:
 | 
				
			|||||||
    *
 | 
					    *
 | 
				
			||||||
    * The order here must match mips/include/trapframe.h.
 | 
					    * The order here must match mips/include/trapframe.h.
 | 
				
			||||||
    *
 | 
					    *
 | 
				
			||||||
    * gdb disassembles this code to try to figure out what registers
 | 
					    * gdb uses the .cfi_offset assembler directives inserted below to
 | 
				
			||||||
    * are where, and it isn't very bright. So in order to make gdb be
 | 
					    * to figure out where each register is stored. Since we've marked
 | 
				
			||||||
    * able to trace the stack back through here, we play some silly
 | 
					    * this function as a "signal handler" with the .cfi_signal_frame
 | 
				
			||||||
    * games.
 | 
					    * directive, gdb won't complain about the fact that the stack
 | 
				
			||||||
 | 
					    * is noncontiguous (if we're coming from userland).
 | 
				
			||||||
    *
 | 
					    *
 | 
				
			||||||
    * In particular:
 | 
					    * We also play a trick with the return address: we mark the ra
 | 
				
			||||||
    *    (1) We store the return address register into the epc slot,
 | 
					    * register as stored to the stack normally and then mark the
 | 
				
			||||||
    *        which makes gdb think it's the return address slot. Then
 | 
					    * return address for *this* function as being in the k1 register
 | 
				
			||||||
    *        we store the real epc value over that.
 | 
					    * using the .cfi_return_column directive. gdb is then able to
 | 
				
			||||||
    *    (2) We store the current sp into the sp slot, which makes gdb
 | 
					    * recognize that the ra we've stored here is the return address
 | 
				
			||||||
    *        think it's the stack pointer slot. Then we store the real
 | 
					    * for the function that was executing when this exception was
 | 
				
			||||||
    *        value.
 | 
					    * taken.
 | 
				
			||||||
    *    (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.
 | 
					 | 
				
			||||||
    *
 | 
					    *
 | 
				
			||||||
    * This logic has not been tested against a recent gdb and has
 | 
					    * All of the cfi (call frame information) material is compiled
 | 
				
			||||||
    * probably bitrotted. Someone(TM) should figure out what gdb
 | 
					    * into the .eh_frame section of the compiled kernel.
 | 
				
			||||||
    * currently expects -- or maybe even patch gdb to understand a
 | 
					 | 
				
			||||||
    * better form of this that doesn't waste so many cycles.
 | 
					 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
   sw ra, 160(sp)	/* dummy for gdb */
 | 
					   sw s8, 148(sp)	/* save s8 */
 | 
				
			||||||
   sw s8, 156(sp)	/* save s8 */
 | 
					   .cfi_offset s8, 148
 | 
				
			||||||
   sw sp, 152(sp)	/* dummy for gdb */
 | 
					   sw k1, 144(sp)	/* real saved sp */
 | 
				
			||||||
   sw gp, 148(sp)	/* save gp */
 | 
					   .cfi_offset sp, 144
 | 
				
			||||||
   sw k1, 144(sp)	/* dummy for gdb */
 | 
					   sw gp, 140(sp)	/* save gp */
 | 
				
			||||||
   sw k0, 140(sp)	/* dummy for gdb */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   sw k1, 152(sp)	/* real saved sp */
 | 
					 | 
				
			||||||
   nop			/* delay slot for store */
 | 
					   nop			/* delay slot for store */
 | 
				
			||||||
 | 
					   .cfi_offset gp, 140
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   .cfi_return_column k1
 | 
				
			||||||
   mfc0 k1, c0_epc	/* Copr.0 reg 13 == PC for exception */
 | 
					   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)
 | 
					   sw t9, 136(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t9, 136
 | 
				
			||||||
   sw t8, 132(sp)
 | 
					   sw t8, 132(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t8, 132
 | 
				
			||||||
   sw s7, 128(sp)
 | 
					   sw s7, 128(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s7, 128
 | 
				
			||||||
   sw s6, 124(sp)
 | 
					   sw s6, 124(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s6, 124
 | 
				
			||||||
   sw s5, 120(sp)
 | 
					   sw s5, 120(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s5, 120
 | 
				
			||||||
   sw s4, 116(sp)
 | 
					   sw s4, 116(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s4, 116
 | 
				
			||||||
   sw s3, 112(sp)
 | 
					   sw s3, 112(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s3, 112
 | 
				
			||||||
   sw s2, 108(sp)
 | 
					   sw s2, 108(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s2, 108
 | 
				
			||||||
   sw s1, 104(sp)
 | 
					   sw s1, 104(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s1, 104
 | 
				
			||||||
   sw s0, 100(sp)
 | 
					   sw s0, 100(sp)
 | 
				
			||||||
 | 
					   .cfi_offset s0, 100
 | 
				
			||||||
   sw t7, 96(sp)
 | 
					   sw t7, 96(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t7, 96
 | 
				
			||||||
   sw t6, 92(sp)
 | 
					   sw t6, 92(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t6, 92
 | 
				
			||||||
   sw t5, 88(sp)
 | 
					   sw t5, 88(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t5, 88
 | 
				
			||||||
   sw t4, 84(sp)
 | 
					   sw t4, 84(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t4, 84
 | 
				
			||||||
   sw t3, 80(sp)
 | 
					   sw t3, 80(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t3, 80
 | 
				
			||||||
   sw t2, 76(sp)
 | 
					   sw t2, 76(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t2, 76
 | 
				
			||||||
   sw t1, 72(sp)
 | 
					   sw t1, 72(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t1, 72
 | 
				
			||||||
   sw t0, 68(sp)
 | 
					   sw t0, 68(sp)
 | 
				
			||||||
 | 
					   .cfi_offset t0, 68
 | 
				
			||||||
   sw a3, 64(sp)
 | 
					   sw a3, 64(sp)
 | 
				
			||||||
 | 
					   .cfi_offset a3, 64
 | 
				
			||||||
   sw a2, 60(sp)
 | 
					   sw a2, 60(sp)
 | 
				
			||||||
 | 
					   .cfi_offset a2, 60
 | 
				
			||||||
   sw a1, 56(sp)
 | 
					   sw a1, 56(sp)
 | 
				
			||||||
 | 
					   .cfi_offset a1, 56
 | 
				
			||||||
   sw a0, 52(sp)
 | 
					   sw a0, 52(sp)
 | 
				
			||||||
 | 
					   .cfi_offset a0, 52
 | 
				
			||||||
   sw v1, 48(sp)
 | 
					   sw v1, 48(sp)
 | 
				
			||||||
 | 
					   .cfi_offset v1, 48
 | 
				
			||||||
   sw v0, 44(sp)
 | 
					   sw v0, 44(sp)
 | 
				
			||||||
 | 
					   .cfi_offset v0, 44
 | 
				
			||||||
   sw AT, 40(sp)
 | 
					   sw AT, 40(sp)
 | 
				
			||||||
 | 
					   .cfi_offset AT, 40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   sw ra, 36(sp)
 | 
					   sw ra, 36(sp)
 | 
				
			||||||
 | 
					   .cfi_offset ra, 36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /*
 | 
					   /*
 | 
				
			||||||
    * Save special registers.
 | 
					    * Save special registers.
 | 
				
			||||||
@@ -227,11 +249,6 @@ common_exception:
 | 
				
			|||||||
   mfc0 t4, c0_cause
 | 
					   mfc0 t4, c0_cause
 | 
				
			||||||
   sw   t4, 24(sp)               /* Copr.0 reg 13 == exception 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.
 | 
					    * Load the curthread register if coming from user mode.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
@@ -260,9 +277,6 @@ common_exception:
 | 
				
			|||||||
   jal mips_trap		/* call it */
 | 
					   jal mips_trap		/* call it */
 | 
				
			||||||
   nop				/* delay slot */
 | 
					   nop				/* delay slot */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /* Something must be here or gdb doesn't find the stack frame. */
 | 
					 | 
				
			||||||
   nop
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   /*
 | 
					   /*
 | 
				
			||||||
    * Now restore stuff and return from the exception.
 | 
					    * Now restore stuff and return from the exception.
 | 
				
			||||||
    * Interrupts should be off.
 | 
					    * Interrupts should be off.
 | 
				
			||||||
@@ -309,20 +323,17 @@ exception_return:
 | 
				
			|||||||
   lw s7, 128(sp)
 | 
					   lw s7, 128(sp)
 | 
				
			||||||
   lw t8, 132(sp)
 | 
					   lw t8, 132(sp)
 | 
				
			||||||
   lw t9, 136(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 */
 | 
					   lw sp, 144(sp)		/* fetch saved sp (must be last) */
 | 
				
			||||||
   /*     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) */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /* done */
 | 
					   /* done */
 | 
				
			||||||
   jr k0			/* jump back */
 | 
					   jr k1			/* jump back */
 | 
				
			||||||
   rfe				/* in delay slot */
 | 
					   rfe				/* in delay slot */
 | 
				
			||||||
 | 
					   .cfi_endproc
 | 
				
			||||||
   .end common_exception
 | 
					   .end common_exception
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,8 +130,8 @@ mips_trap(struct trapframe *tf)
 | 
				
			|||||||
	bool iskern;
 | 
						bool iskern;
 | 
				
			||||||
	int spl;
 | 
						int spl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The trap frame is supposed to be 37 registers long. */
 | 
						/* The trap frame is supposed to be 35 registers long. */
 | 
				
			||||||
	KASSERT(sizeof(struct trapframe)==(37*4));
 | 
						KASSERT(sizeof(struct trapframe)==(35*4));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Extract the exception code info from the register fields.
 | 
						 * Extract the exception code info from the register fields.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,14 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * These arrays are also used to start up new CPUs, for roughly the
 | 
					 * These arrays are also used to start up new CPUs, for roughly the
 | 
				
			||||||
 * same reasons.
 | 
					 * 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];
 | 
					vaddr_t cpustacks[MAXCPUS];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@
 | 
				
			|||||||
#include <mainbus.h>
 | 
					#include <mainbus.h>
 | 
				
			||||||
#include <sys161/bus.h>
 | 
					#include <sys161/bus.h>
 | 
				
			||||||
#include <lamebus/lamebus.h>
 | 
					#include <lamebus/lamebus.h>
 | 
				
			||||||
 | 
					#include <lamebus/ltrace.h>
 | 
				
			||||||
#include "autoconf.h"
 | 
					#include "autoconf.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -275,6 +276,15 @@ mainbus_send_ipi(struct cpu *target)
 | 
				
			|||||||
	lamebus_assert_ipi(lamebus, target);
 | 
						lamebus_assert_ipi(lamebus, target);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Trigger the debugger.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					mainbus_debugger(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ltrace_stop(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Interrupt dispatcher.
 | 
					 * Interrupt dispatcher.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include conf/conf.kern		# get definitions of available options
 | 
					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.
 | 
					# Device drivers for hardware.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
include conf/conf.kern		# get definitions of available options
 | 
					include conf/conf.kern		# get definitions of available options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#debug				# Optimizing compile (no debug).
 | 
					#debug				# Optimizing compile (no debug).
 | 
				
			||||||
 | 
					#debugonly
 | 
				
			||||||
options noasserts		# Disable assertions.
 | 
					options noasserts		# Disable assertions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
include conf/conf.kern		# get definitions of available options
 | 
					include conf/conf.kern		# get definitions of available options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
debug				# Compile with debug info.
 | 
					debug				# Compile with debug info.
 | 
				
			||||||
 | 
					#debugonly			# Compile with debug info only (no -Og).
 | 
				
			||||||
 | 
					#options hangman 		# Deadlock detection. (off by default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Device drivers for hardware.
 | 
					# Device drivers for hardware.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
include conf/conf.kern		# get definitions of available options
 | 
					include conf/conf.kern		# get definitions of available options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#debug				# Optimizing compile (no debug).
 | 
					#debug				# Optimizing compile (no debug).
 | 
				
			||||||
 | 
					#debugonly
 | 
				
			||||||
options noasserts		# Disable assertions.
 | 
					options noasserts		# Disable assertions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -334,6 +334,9 @@ file      thread/synch.c
 | 
				
			|||||||
file      thread/thread.c
 | 
					file      thread/thread.c
 | 
				
			||||||
file      thread/threadlist.c
 | 
					file      thread/threadlist.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defoption hangman
 | 
				
			||||||
 | 
					optfile   hangman thread/hangman.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Process system
 | 
					# Process system
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@
 | 
				
			|||||||
# Recognized directives:
 | 
					# Recognized directives:
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#    file <filename>          use source file
 | 
					#    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
 | 
					#    defoption <sym>          define an option
 | 
				
			||||||
#    optfile <sym> <file>     if option <sym> is enabled, use file <file>
 | 
					#    optfile <sym> <file>     if option <sym> is enabled, use file <file>
 | 
				
			||||||
#    optofffile <sym> <file>  if option <sym> is disabled, 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["include"] = 2;
 | 
				
			||||||
	nfields["file"] = 2;
 | 
						nfields["file"] = 2;
 | 
				
			||||||
	nfields["debug"] = 1;
 | 
						nfields["debug"] = 1;
 | 
				
			||||||
 | 
						nfields["debugonly"] = 1;
 | 
				
			||||||
	nfields["defoption"] = 2;
 | 
						nfields["defoption"] = 2;
 | 
				
			||||||
	nfields["optfile"] = 3;
 | 
						nfields["optfile"] = 3;
 | 
				
			||||||
	nfields["optofffile"] = 3;
 | 
						nfields["optofffile"] = 3;
 | 
				
			||||||
@@ -776,6 +778,9 @@ echo -n ' files.mk'
 | 
				
			|||||||
	# Default: optimize.
 | 
						# Default: optimize.
 | 
				
			||||||
	BEGIN { debugflags="-O2"; }
 | 
						BEGIN { debugflags="-O2"; }
 | 
				
			||||||
	$1=="debug" {
 | 
						$1=="debug" {
 | 
				
			||||||
 | 
						    debugflags="-g -Og";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						$1=="debugonly" {
 | 
				
			||||||
	    debugflags="-g";
 | 
						    debugflags="-g";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										40
									
								
								kern/gdbscripts/mips-userland
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								kern/gdbscripts/mips-userland
									
									
									
									
									
										Normal 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,6 +88,11 @@ struct cpu {
 | 
				
			|||||||
	struct tlbshootdown c_shootdown[TLBSHOOTDOWN_MAX];
 | 
						struct tlbshootdown c_shootdown[TLBSHOOTDOWN_MAX];
 | 
				
			||||||
	unsigned c_numshootdown;
 | 
						unsigned c_numshootdown;
 | 
				
			||||||
	struct spinlock c_ipi_lock;
 | 
						struct spinlock c_ipi_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Accessed by other cpus. Protected inside hangman.c.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						HANGMAN_ACTOR(c_hangman);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										84
									
								
								kern/include/hangman.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								kern/include/hangman.h
									
									
									
									
									
										Normal 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 */
 | 
				
			||||||
@@ -194,7 +194,7 @@ void kprintf_bootstrap(void);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DIVROUNDUP(a,b) (((a)+(b)-1)/(b))
 | 
					#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_ */
 | 
					#endif /* _LIB_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,9 @@ size_t mainbus_ramsize(void);
 | 
				
			|||||||
/* Switch on an inter-processor interrupt. (Low-level.) */
 | 
					/* Switch on an inter-processor interrupt. (Low-level.) */
 | 
				
			||||||
void mainbus_send_ipi(struct cpu *target);
 | 
					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
 | 
					 * The various ways to shut down the system. (These are very low-level
 | 
				
			||||||
 * and should generally not be called directly - md_poweroff, for
 | 
					 * and should generally not be called directly - md_poweroff, for
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cdefs.h>
 | 
					#include <cdefs.h>
 | 
				
			||||||
 | 
					#include <hangman.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Inlining support - for making sure an out-of-line copy gets built */
 | 
					/* Inlining support - for making sure an out-of-line copy gets built */
 | 
				
			||||||
#ifndef SPINLOCK_INLINE
 | 
					#ifndef SPINLOCK_INLINE
 | 
				
			||||||
@@ -57,12 +58,18 @@
 | 
				
			|||||||
struct spinlock {
 | 
					struct spinlock {
 | 
				
			||||||
	volatile spinlock_data_t splk_lock; /* Memory word where we spin. */
 | 
						volatile spinlock_data_t splk_lock; /* Memory word where we spin. */
 | 
				
			||||||
	struct cpu *splk_holder;	    /* CPU holding this lock. */
 | 
						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.
 | 
					 * 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 }
 | 
					#define SPINLOCK_INITIALIZER	{ SPINLOCK_DATA_INITIALIZER, NULL }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Spinlock functions.
 | 
					 * Spinlock functions.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,6 +74,7 @@ void V(struct semaphore *);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
struct lock {
 | 
					struct lock {
 | 
				
			||||||
        char *lk_name;
 | 
					        char *lk_name;
 | 
				
			||||||
 | 
					        HANGMAN_LOCKABLE(lk_hangman);   /* Deadlock detector hook. */
 | 
				
			||||||
        // add what you need here
 | 
					        // add what you need here
 | 
				
			||||||
        // (don't forget to mark things volatile as needed)
 | 
					        // (don't forget to mark things volatile as needed)
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -93,6 +93,7 @@ struct thread {
 | 
				
			|||||||
	struct switchframe *t_context;	/* Saved register context (on stack) */
 | 
						struct switchframe *t_context;	/* Saved register context (on stack) */
 | 
				
			||||||
	struct cpu *t_cpu;		/* CPU thread runs on */
 | 
						struct cpu *t_cpu;		/* CPU thread runs on */
 | 
				
			||||||
	struct proc *t_proc;		/* Process thread belongs to */
 | 
						struct proc *t_proc;		/* Process thread belongs to */
 | 
				
			||||||
 | 
						HANGMAN_ACTOR(t_hangman);	/* Deadlock detector hook */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Interrupt state fields.
 | 
						 * Interrupt state fields.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@
 | 
				
			|||||||
 * Leave this alone, so we can tell what version of the OS/161 base
 | 
					 * Leave this alone, so we can tell what version of the OS/161 base
 | 
				
			||||||
 * code we gave you.
 | 
					 * 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.
 | 
					 * Change this as you see fit in the course of hacking the system.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,8 @@
 | 
				
			|||||||
#include <lib.h>
 | 
					#include <lib.h>
 | 
				
			||||||
#include <uio.h>
 | 
					#include <uio.h>
 | 
				
			||||||
#include <clock.h>
 | 
					#include <clock.h>
 | 
				
			||||||
 | 
					#include <mainbus.h>
 | 
				
			||||||
 | 
					#include <synch.h>
 | 
				
			||||||
#include <thread.h>
 | 
					#include <thread.h>
 | 
				
			||||||
#include <proc.h>
 | 
					#include <proc.h>
 | 
				
			||||||
#include <vfs.h>
 | 
					#include <vfs.h>
 | 
				
			||||||
@@ -247,6 +249,21 @@ cmd_sync(int nargs, char **args)
 | 
				
			|||||||
	return 0;
 | 
						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.
 | 
					 * Command for doing an intentional panic.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -261,6 +278,81 @@ cmd_panic(int nargs, char **args)
 | 
				
			|||||||
	return 0;
 | 
						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.
 | 
					 * Command for shutting down.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -463,7 +555,9 @@ static const char *opsmenu[] = {
 | 
				
			|||||||
	"[cd]      Change directory          ",
 | 
						"[cd]      Change directory          ",
 | 
				
			||||||
	"[pwd]     Print current directory   ",
 | 
						"[pwd]     Print current directory   ",
 | 
				
			||||||
	"[sync]    Sync filesystems          ",
 | 
						"[sync]    Sync filesystems          ",
 | 
				
			||||||
 | 
						"[debug]   Drop to debugger          ",
 | 
				
			||||||
	"[panic]   Intentional panic         ",
 | 
						"[panic]   Intentional panic         ",
 | 
				
			||||||
 | 
						"[deadlock] Intentional deadlock     ",
 | 
				
			||||||
	"[q]       Quit and shut down        ",
 | 
						"[q]       Quit and shut down        ",
 | 
				
			||||||
	NULL
 | 
						NULL
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -614,7 +708,9 @@ static struct {
 | 
				
			|||||||
	{ "cd",		cmd_chdir },
 | 
						{ "cd",		cmd_chdir },
 | 
				
			||||||
	{ "pwd",	cmd_pwd },
 | 
						{ "pwd",	cmd_pwd },
 | 
				
			||||||
	{ "sync",	cmd_sync },
 | 
						{ "sync",	cmd_sync },
 | 
				
			||||||
 | 
						{ "debug",	cmd_debug },
 | 
				
			||||||
	{ "panic",	cmd_panic },
 | 
						{ "panic",	cmd_panic },
 | 
				
			||||||
 | 
						{ "deadlock",	cmd_deadlock },
 | 
				
			||||||
	{ "q",		cmd_quit },
 | 
						{ "q",		cmd_quit },
 | 
				
			||||||
	{ "exit",	cmd_quit },
 | 
						{ "exit",	cmd_quit },
 | 
				
			||||||
	{ "halt",	cmd_quit },
 | 
						{ "halt",	cmd_quit },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,6 +156,9 @@ arraytest2(int nargs, char **args)
 | 
				
			|||||||
	(void)nargs;
 | 
						(void)nargs;
 | 
				
			||||||
	(void)args;
 | 
						(void)args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Silence warning with gcc 4.8 -Og (but not -O2) */
 | 
				
			||||||
 | 
						x = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kprintf("Beginning large array test...\n");
 | 
						kprintf("Beginning large array test...\n");
 | 
				
			||||||
	a = array_create();
 | 
						a = array_create();
 | 
				
			||||||
	KASSERT(a != NULL);
 | 
						KASSERT(a != NULL);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -681,7 +681,7 @@ checkfilesystem(int nargs, char **args)
 | 
				
			|||||||
	char *device;
 | 
						char *device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nargs != 2) {
 | 
						if (nargs != 2) {
 | 
				
			||||||
		kprintf("Usage: fs[12345] filesystem:\n");
 | 
							kprintf("Usage: fs[123456] filesystem:\n");
 | 
				
			||||||
		return EINVAL;
 | 
							return EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										182
									
								
								kern/thread/hangman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								kern/thread/hangman.c
									
									
									
									
									
										Normal 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -52,6 +52,7 @@ spinlock_init(struct spinlock *splk)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	spinlock_data_set(&splk->splk_lock, 0);
 | 
						spinlock_data_set(&splk->splk_lock, 0);
 | 
				
			||||||
	splk->splk_holder = NULL;
 | 
						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);
 | 
								panic("Deadlock on spinlock %p\n", splk);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		mycpu->c_spinlocks++;
 | 
							mycpu->c_spinlocks++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							HANGMAN_WAIT(&curcpu->c_hangman, &splk->splk_hangman);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		mycpu = NULL;
 | 
							mycpu = NULL;
 | 
				
			||||||
@@ -112,6 +115,10 @@ spinlock_acquire(struct spinlock *splk)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	membar_store_any();
 | 
						membar_store_any();
 | 
				
			||||||
	splk->splk_holder = mycpu;
 | 
						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(splk->splk_holder == curcpu->c_self);
 | 
				
			||||||
		KASSERT(curcpu->c_spinlocks > 0);
 | 
							KASSERT(curcpu->c_spinlocks > 0);
 | 
				
			||||||
		curcpu->c_spinlocks--;
 | 
							curcpu->c_spinlocks--;
 | 
				
			||||||
 | 
							HANGMAN_RELEASE(&curcpu->c_hangman, &splk->splk_hangman);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	splk->splk_holder = NULL;
 | 
						splk->splk_holder = NULL;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -154,6 +154,8 @@ lock_create(const char *name)
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HANGMAN_LOCKABLEINIT(&lock->lk_hangman, lock->lk_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// add stuff here as needed
 | 
						// add stuff here as needed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return lock;
 | 
						return lock;
 | 
				
			||||||
@@ -173,14 +175,23 @@ lock_destroy(struct lock *lock)
 | 
				
			|||||||
void
 | 
					void
 | 
				
			||||||
lock_acquire(struct lock *lock)
 | 
					lock_acquire(struct lock *lock)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* Call this (atomically) before waiting for a lock */
 | 
				
			||||||
 | 
						//HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Write this
 | 
						// Write this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(void)lock;  // suppress warning until code gets written
 | 
						(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
 | 
					void
 | 
				
			||||||
lock_release(struct lock *lock)
 | 
					lock_release(struct lock *lock)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* Call this (atomically) when the lock is released */
 | 
				
			||||||
 | 
						//HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Write this
 | 
						// Write this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	(void)lock;  // suppress warning until code gets written
 | 
						(void)lock;  // suppress warning until code gets written
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,6 +145,7 @@ thread_create(const char *name)
 | 
				
			|||||||
	thread->t_context = NULL;
 | 
						thread->t_context = NULL;
 | 
				
			||||||
	thread->t_cpu = NULL;
 | 
						thread->t_cpu = NULL;
 | 
				
			||||||
	thread->t_proc = NULL;
 | 
						thread->t_proc = NULL;
 | 
				
			||||||
 | 
						HANGMAN_ACTORINIT(&thread->t_hangman, thread->t_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Interrupt state fields */
 | 
						/* Interrupt state fields */
 | 
				
			||||||
	thread->t_in_interrupt = false;
 | 
						thread->t_in_interrupt = false;
 | 
				
			||||||
@@ -244,6 +245,8 @@ cpu_create(unsigned hardware_number)
 | 
				
			|||||||
		curcpu->c_curthread = curthread;
 | 
							curcpu->c_curthread = curthread;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HANGMAN_ACTORINIT(&c->c_hangman, "cpu");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result = proc_addthread(kproc, c->c_curthread);
 | 
						result = proc_addthread(kproc, c->c_curthread);
 | 
				
			||||||
	if (result) {
 | 
						if (result) {
 | 
				
			||||||
		panic("cpu_create: proc_addthread:: %s\n", strerror(result));
 | 
							panic("cpu_create: proc_addthread:: %s\n", strerror(result));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,6 +129,23 @@ vfs_biglock_acquire(void)
 | 
				
			|||||||
	if (!lock_do_i_hold(vfs_biglock)) {
 | 
						if (!lock_do_i_hold(vfs_biglock)) {
 | 
				
			||||||
		lock_acquire(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++;
 | 
						vfs_biglock_depth++;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -381,6 +398,9 @@ vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs)
 | 
				
			|||||||
	unsigned index;
 | 
						unsigned index;
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Silence warning with gcc 4.8 -Og (but not -O2) */
 | 
				
			||||||
 | 
						index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vfs_biglock_acquire();
 | 
						vfs_biglock_acquire();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	name = kstrdup(dname);
 | 
						name = kstrdup(dname);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -135,6 +135,13 @@ getdevice(char *path, char **subpath, struct vnode **startvn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	KASSERT(vfs_biglock_do_i_hold());
 | 
						KASSERT(vfs_biglock_do_i_hold());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Entirely empty filenames aren't legal.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (path[0] == 0) {
 | 
				
			||||||
 | 
							return EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Locate the first colon or slash.
 | 
						 * Locate the first colon or slash.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1113,6 +1113,10 @@ subpage_kfree(void *ptr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	checksubpages();
 | 
						checksubpages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Silence warnings with gcc 4.8 -Og (but not -O2) */
 | 
				
			||||||
 | 
						prpage = 0;
 | 
				
			||||||
 | 
						blktype = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (pr = allbase; pr; pr = pr->next_all) {
 | 
						for (pr = allbase; pr; pr = pr->next_all) {
 | 
				
			||||||
		prpage = PR_PAGEADDR(pr);
 | 
							prpage = PR_PAGEADDR(pr);
 | 
				
			||||||
		blktype = PR_BLOCKTYPE(pr);
 | 
							blktype = PR_BLOCKTYPE(pr);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# MKDIRS logic
 | 
					# OS/161 build environment: MKDIRS logic
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This generates rules for all intermediate directories as well as
 | 
					# This generates rules for all intermediate directories as well as
 | 
				
			||||||
# the directories listed. (That is, if you say MKDIRS=/usr/bin/foo
 | 
					# the directories listed. (That is, if you say MKDIRS=/usr/bin/foo
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										92
									
								
								mk/os161.script.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								mk/os161.script.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# OS/161 build environment: install scripts
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Usage:
 | 
				
			||||||
 | 
					#    TOP=../..
 | 
				
			||||||
 | 
					#    .include "$(TOP)/mk/os161.config.mk"
 | 
				
			||||||
 | 
					#    [defs go here]
 | 
				
			||||||
 | 
					#    .include "$(TOP)/mk/os161.man.mk"
 | 
				
			||||||
 | 
					#    [any extra rules go here]
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Variables controlling this file:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# EXECSCRIPTS			Executable files to install.
 | 
				
			||||||
 | 
					# NONEXECSCRIPTS		Non-executable files to install.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# SCRIPTDIR			Directory under $(OSTREE) to install into,
 | 
				
			||||||
 | 
					#                               e.g. /hostbin. Should have a leading slash.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALLSCRIPTS=$(NONEXECSCRIPTS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# We may want these directories created. (Used by os161.baserules.mk.)
 | 
				
			||||||
 | 
					MKDIRS+=$(MYBUILDDIR)
 | 
				
			||||||
 | 
					MKDIRS+=$(INSTALLTOP)$(SCRIPTDIR)
 | 
				
			||||||
 | 
					MKDIRS+=$(OSTREE)$(SCRIPTDIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Default rule: "build" the executable scripts. This sets the hash-bang
 | 
				
			||||||
 | 
					# header with the interpreter path.
 | 
				
			||||||
 | 
					# (In make the first rule found is the default.)
 | 
				
			||||||
 | 
					all: all-local
 | 
				
			||||||
 | 
					all-local: $(MYBUILDDIR) .WAIT
 | 
				
			||||||
 | 
					.for S in $(EXECSCRIPTS)
 | 
				
			||||||
 | 
					ALLSCRIPTS+=$(MYBUILDDIR)/$(S)
 | 
				
			||||||
 | 
					all-local: $(MYBUILDDIR)/$(S)
 | 
				
			||||||
 | 
					$(MYBUILDDIR)/$(S): $(S)
 | 
				
			||||||
 | 
					# This must test $@, or assign another variable; it can't test $(S).
 | 
				
			||||||
 | 
					# (This is a bmake bug.)
 | 
				
			||||||
 | 
					.if !empty(@:M*.py)
 | 
				
			||||||
 | 
						echo '#!'"$(PYTHON_INTERPRETER)" > $@.new
 | 
				
			||||||
 | 
					.else
 | 
				
			||||||
 | 
						sed -n -e '1p' < $(S) > $@.new
 | 
				
			||||||
 | 
					.endif
 | 
				
			||||||
 | 
						sed -e '1d' < $(S) >> $@.new
 | 
				
			||||||
 | 
						chmod 755 $@.new
 | 
				
			||||||
 | 
						mv -f $@.new $@
 | 
				
			||||||
 | 
					.endfor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# depend doesn't need to do anything
 | 
				
			||||||
 | 
					depend-local: ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Install: we can install into either $(INSTALLTOP) or $(OSTREE).
 | 
				
			||||||
 | 
					# When building the whole system, we always install into the staging
 | 
				
			||||||
 | 
					# area. However, if you're working on a particular program it is
 | 
				
			||||||
 | 
					# usually convenient to be able to install it directly to $(OSTREE)
 | 
				
			||||||
 | 
					# instead of doing a complete top-level install.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Note that we make a hard link instead of a copy by default to reduce
 | 
				
			||||||
 | 
					# overhead.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					install-staging-local: $(INSTALLTOP)$(SCRIPTDIR) .WAIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.for _F_ in $(ALLSCRIPTS)
 | 
				
			||||||
 | 
					install-staging-local: $(INSTALLTOP)$(SCRIPTDIR)/$(_F_:T)
 | 
				
			||||||
 | 
					$(INSTALLTOP)$(SCRIPTDIR)/$(_F_:T): $(_F_)
 | 
				
			||||||
 | 
						rm -f $(.TARGET)
 | 
				
			||||||
 | 
						ln $(_F_) $(.TARGET) || cp $(_F_) $(.TARGET)
 | 
				
			||||||
 | 
					.endfor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install-local: $(OSTREE)$(SCRIPTDIR) .WAIT installscripts
 | 
				
			||||||
 | 
					installscripts:
 | 
				
			||||||
 | 
					.for _F_ in $(ALLSCRIPTS)
 | 
				
			||||||
 | 
						rm -f $(OSTREE)$(SCRIPTDIR)/$(_F_:T)
 | 
				
			||||||
 | 
						ln $(_F_) $(OSTREE)$(SCRIPTDIR)/$(_F_:T) || \
 | 
				
			||||||
 | 
						  cp $(_F_) $(OSTREE)$(SCRIPTDIR)/$(_F_:T)
 | 
				
			||||||
 | 
					.endfor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# clean: remove build products
 | 
				
			||||||
 | 
					clean-local:
 | 
				
			||||||
 | 
					.for S in $(EXECSCRIPTS)
 | 
				
			||||||
 | 
						rm -f $(MYBUILDDIR)/$(S)
 | 
				
			||||||
 | 
					.endfor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mark targets that don't represent files PHONY, to prevent various
 | 
				
			||||||
 | 
					# lossage if files by those names appear.
 | 
				
			||||||
 | 
					.PHONY: all all-local install-staging-local install-local installscripts
 | 
				
			||||||
 | 
					.PHONY: clean-local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Finally, get the shared definitions for the most basic rules.
 | 
				
			||||||
 | 
					.include "$(TOP)/mk/os161.baserules.mk"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# End.
 | 
				
			||||||
@@ -177,7 +177,7 @@ print(const char *path)
 | 
				
			|||||||
			typech = '?';
 | 
								typech = '?';
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printf("%crwx------ %2d root  %-8llu",
 | 
							printf("%crwx------ %2d root  %-7llu ",
 | 
				
			||||||
		       typech,
 | 
							       typech,
 | 
				
			||||||
		       statbuf.st_nlink,
 | 
							       statbuf.st_nlink,
 | 
				
			||||||
		       statbuf.st_size);
 | 
							       statbuf.st_size);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -197,11 +197,9 @@ dumpdata(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	indexsize = dolseek(indexfd, indexname, 0, SEEK_CUR);
 | 
						indexsize = dolseek(indexfd, indexname, 0, SEEK_CUR);
 | 
				
			||||||
	pos = indexsize;
 | 
						pos = indexsize;
 | 
				
			||||||
	while (1) {
 | 
						assert(pos % sizeof(x) == 0);
 | 
				
			||||||
 | 
						while (pos > 0) {
 | 
				
			||||||
		pos -= sizeof(x);
 | 
							pos -= sizeof(x);
 | 
				
			||||||
		if (pos == 0) {
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		assert(pos >= 0);
 | 
							assert(pos >= 0);
 | 
				
			||||||
		dolseek(indexfd, indexname, pos, SEEK_SET);
 | 
							dolseek(indexfd, indexname, pos, SEEK_SET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,6 +69,11 @@ pipe_unaligned(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	rv = pipe((int *)ptr);
 | 
						rv = pipe((int *)ptr);
 | 
				
			||||||
	report_survival(rv, errno, &result);
 | 
						report_survival(rv, errno, &result);
 | 
				
			||||||
 | 
						if (rv == 0) {
 | 
				
			||||||
 | 
							memmove(fds, ptr, 2*sizeof(int));
 | 
				
			||||||
 | 
							close(fds[0]);
 | 
				
			||||||
 | 
							close(fds[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@
 | 
				
			|||||||
int
 | 
					int
 | 
				
			||||||
main(int argc, char *argv[])
 | 
					main(int argc, char *argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char writebuf[40] = "Twiddle dee dee, Twiddle dum dum.......\n";
 | 
						static char writebuf[41] = "Twiddle dee dee, Twiddle dum dum.......\n";
 | 
				
			||||||
	static char readbuf[41];
 | 
						static char readbuf[41];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *file;
 | 
						const char *file;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -152,12 +152,20 @@ void
 | 
				
			|||||||
test(int nowait)
 | 
					test(int nowait)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int pid0, pid1, pid2, pid3;
 | 
						int pid0, pid1, pid2, pid3;
 | 
				
			||||||
 | 
						int depth = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Caution: This generates processes geometrically.
 | 
						 * Caution: This generates processes geometrically.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * It is unrolled to encourage gcc to registerize the pids,
 | 
						 * It is unrolled to encourage gcc to registerize the pids,
 | 
				
			||||||
	 * to prevent wait/exit problems if fork corrupts memory.
 | 
						 * to prevent wait/exit problems if fork corrupts memory.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Note: if the depth prints trigger and show that the depth
 | 
				
			||||||
 | 
						 * is too small, the most likely explanation is that the fork
 | 
				
			||||||
 | 
						 * child is returning from the write() inside putchar()
 | 
				
			||||||
 | 
						 * instead of from fork() and thus skipping the depth++. This
 | 
				
			||||||
 | 
						 * is a fairly common problem caused by races in the kernel
 | 
				
			||||||
 | 
						 * fork code.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
@@ -184,18 +192,37 @@ test(int nowait)
 | 
				
			|||||||
	pid0 = dofork();
 | 
						pid0 = dofork();
 | 
				
			||||||
	nprintf(".");
 | 
						nprintf(".");
 | 
				
			||||||
	write(fd, "A", 1);
 | 
						write(fd, "A", 1);
 | 
				
			||||||
 | 
						depth++;
 | 
				
			||||||
 | 
						if (depth != 1) {
 | 
				
			||||||
 | 
							warnx("depth %d, should be 1", depth);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	check();
 | 
						check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pid1 = dofork();
 | 
						pid1 = dofork();
 | 
				
			||||||
	nprintf(".");
 | 
						nprintf(".");
 | 
				
			||||||
	write(fd, "B", 1);
 | 
						write(fd, "B", 1);
 | 
				
			||||||
 | 
						depth++;
 | 
				
			||||||
 | 
						if (depth != 2) {
 | 
				
			||||||
 | 
							warnx("depth %d, should be 2", depth);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	check();
 | 
						check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pid2 = dofork();
 | 
						pid2 = dofork();
 | 
				
			||||||
	nprintf(".");
 | 
						nprintf(".");
 | 
				
			||||||
	write(fd, "C", 1);
 | 
						write(fd, "C", 1);
 | 
				
			||||||
 | 
						depth++;
 | 
				
			||||||
 | 
						if (depth != 3) {
 | 
				
			||||||
 | 
							warnx("depth %d, should be 3", depth);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	check();
 | 
						check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pid3 = dofork();
 | 
						pid3 = dofork();
 | 
				
			||||||
	nprintf(".");
 | 
						nprintf(".");
 | 
				
			||||||
	write(fd, "D", 1);
 | 
						write(fd, "D", 1);
 | 
				
			||||||
 | 
						depth++;
 | 
				
			||||||
 | 
						if (depth != 4) {
 | 
				
			||||||
 | 
							warnx("depth %d, should be 4", depth);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	check();
 | 
						check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@
 | 
				
			|||||||
 * hog.c
 | 
					 * hog.c
 | 
				
			||||||
 * 	Spawned by several other user programs to test time-slicing.
 | 
					 * 	Spawned by several other user programs to test time-slicing.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This does not differ from guzzle in any important way.
 | 
					 * Loops consuming CPU cycles.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,6 +134,7 @@ semP(struct usem *sem, size_t num)
 | 
				
			|||||||
	if (read(sem->fd, c, num) < 0) {
 | 
						if (read(sem->fd, c, num) < 0) {
 | 
				
			||||||
		err(1, "%s: read", sem->name);
 | 
							err(1, "%s: read", sem->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						(void)c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -273,16 +273,24 @@ static
 | 
				
			|||||||
void
 | 
					void
 | 
				
			||||||
semP(struct usem *sem, size_t num)
 | 
					semP(struct usem *sem, size_t num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (read(sem->fd, NULL, num) < 0) {
 | 
						char c[num];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (read(sem->fd, c, num) < 0) {
 | 
				
			||||||
		err(1, "%s: read", sem->name);
 | 
							err(1, "%s: read", sem->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						(void)c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
semV(struct usem *sem, size_t num)
 | 
					semV(struct usem *sem, size_t num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (write(sem->fd, NULL, num) < 0) {
 | 
						char c[num];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* semfs does not use these values, but be conservative */
 | 
				
			||||||
 | 
						memset(c, 0, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (write(sem->fd, c, num) < 0) {
 | 
				
			||||||
		err(1, "%s: write", sem->name);
 | 
							err(1, "%s: write", sem->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -326,7 +334,12 @@ makeprocs(bool dowait)
 | 
				
			|||||||
	for (i=0; i<NJOBS; i++) {
 | 
						for (i=0; i<NJOBS; i++) {
 | 
				
			||||||
		pids[i] = fork();
 | 
							pids[i] = fork();
 | 
				
			||||||
		if (pids[i]<0) {
 | 
							if (pids[i]<0) {
 | 
				
			||||||
			warn("fork");
 | 
								warn("fork (process %d)", i);
 | 
				
			||||||
 | 
								if (dowait) {
 | 
				
			||||||
 | 
									semopen(&s1);
 | 
				
			||||||
 | 
									semV(&s1, 1);
 | 
				
			||||||
 | 
									semclose(&s1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (pids[i]==0) {
 | 
							if (pids[i]==0) {
 | 
				
			||||||
			/* child */
 | 
								/* child */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdarg.h>
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <err.h>
 | 
					#include <err.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -84,9 +85,9 @@ void
 | 
				
			|||||||
Pn(struct usem *sem, unsigned count)
 | 
					Pn(struct usem *sem, unsigned count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t r;
 | 
						ssize_t r;
 | 
				
			||||||
	char c;
 | 
						char c[count];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r = read(sem->fd, &c, count);
 | 
						r = read(sem->fd, c, count);
 | 
				
			||||||
	if (r < 0) {
 | 
						if (r < 0) {
 | 
				
			||||||
		err(1, "%s: read", sem->name);
 | 
							err(1, "%s: read", sem->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -105,9 +106,12 @@ void
 | 
				
			|||||||
Vn(struct usem *sem, unsigned count)
 | 
					Vn(struct usem *sem, unsigned count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t r;
 | 
						ssize_t r;
 | 
				
			||||||
	char c;
 | 
						char c[count];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r = write(sem->fd, &c, count);
 | 
						/* semfs does not use these values, but be conservative */
 | 
				
			||||||
 | 
						memset(c, 0, count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r = write(sem->fd, c, count);
 | 
				
			||||||
	if (r < 0) {
 | 
						if (r < 0) {
 | 
				
			||||||
		err(1, "%s: write", sem->name);
 | 
							err(1, "%s: write", sem->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user