/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * $Log:	vm_kmap.h,v $
 * Revision 1.1.2.4  92/04/24  09:31:58  Robert_Picco
 * 	Fixed kernel map entry lock retry logic
 * 	[92/04/16  09:21:08  Robert_Picco]
 * 
 * Revision 1.1.2.3  92/03/10  09:57:32  Ronald_Widyono
 * 	bmerge with AG
 * 	[92/03/09  23:43:32  Ronald_Widyono]
 * 
 * 	Remove UNIX_LOCKS conditional.  simple_lock_addr() handles everything
 * 	[92/03/04  16:11:08  Ronald_Widyono]
 * 
 * 	Use simple_lock_addr() macro when passing simple lock addresses.
 * 	Fixes broken RT kernel build.
 * 	[92/03/03  02:21:02  Ronald_Widyono]
 * 
 * Revision 1.1.2.2  92/02/26  15:54:31  Charles_Briggs
 * 	UBC merge.
 * 	[92/02/22  15:05:18  Charles_Briggs]
 * 
 * $EndLog$
 */
/*
 * @(#)$RCSfile: vm_kmap.h,v $ $Revision: 1.1.2.4 $ (DEC) $Date: 92/04/24 09:31:58 $
 */
#ifndef	__VM_KMAP__
#define	__VM_KMAP__ 1
#include <kern/sched_prim.h>
#include <sys/unix_defs.h>
#include <sys/param.h>

/*
 * The kernel lock fault strategy is unlike that for the U maps and C maps.
 * It would be hazardous to hold a map write lock waiting for faults to
 * complete.  For that matter it could result in a deadlock.  Instead for
 * the kernel we let write lock synchronize themselves at the map level.
 * A write lock proceeds to operate until it encounters a map entry with
 * fault activity.  The operation releases the map write lock while holding
 * the map entry fault lock.  It indicates its desire to modify the map
 * entry by updating the entry's want field.  Other writers who progress
 * to this map entry will do the same if their intent of crossing the
 * map entry is anything other than list traversal. All operations are in a 
 * retry mode.  A finishing faulter checks to see if the want bit is set.  It
 * does so with the entry fault lock taken.  If there are writers waiting
 * on the entry, then they are all awakened and race to acquire the write
 * lock once again.  All map entry routine a passed the entry with the
 * fault lock taken and the map write locked.  The handle should release the
 * map write lock as quickly as possibly to enable other map activity 
 * to proceed.
 *
 * All write map entry operation handles have a fault lock acquired for
 * them and the map is passed write locked.  This is true because
 * the entry faultlock couldn't have been acquired if there was
 * any fault activity.  The entry operation is assumed to release
 * the map write lock before engaging in any activity which could suspend
 * the thread executing the code.  When the operation completes the fault lock
 * is released by the upper level map operation routine.
 *
 * The vm_mape_faultlock is called by a thread that has
 * the address map write locked.  Pagefaults always
 * precede map modification requests; such as
 * protection, deletion and wiring.
 */


#define vm_mape_faultlock(VME,RETRY) {					\
	if ((VME)->vme_faults) {					\
		usimple_lock(&(VME)->vme_faultlock);			\
		if ((VME)->vme_faults) {				\
			vm_map_unlock((VME)->vme_map);			\
			(VME)->vme_want++;				\
			assert_wait((vm_offset_t) (VME), FALSE);	\
			usimple_unlock(&(VME)->vme_faultlock);		\
			thread_block();					\
			RETRY;						\
		}							\
		else usimple_unlock(&(VME)->vme_faultlock);		\
	}								\
}

#define vm_mape_fault(VME) {						\
	usimple_lock(&(VME)->vme_faultlock);		 		\
	(VME)->vme_faults++;						\
	usimple_unlock(&(VME)->vme_faultlock);				\
}

#define vm_mape_faultdone(VME) {					\
	usimple_lock(&(VME)->vme_faultlock);				\
	(VME)->vme_faults--;						\
	if ((VME)->vme_faults == 0 && (VME)->vme_want) {		\
		(VME)->vme_want = 0;					\
		thread_wakeup((vm_offset_t) (VME));			\
	}								\
	usimple_unlock(&(VME)->vme_faultlock);				\
}

#endif /* !__VM_KMAP__ */
