diff -Nur orig/pnet/engine/dumpconfig.c work.xxx/pnet/engine/dumpconfig.c
--- orig/pnet/engine/dumpconfig.c	2003-07-23 09:05:37.000000000 +1000
+++ work.xxx/pnet/engine/dumpconfig.c	2004-05-04 18:40:50.000000000 +1000
@@ -158,10 +158,10 @@
 
 	if(level>1)
 	{
-	#ifdef USE_HASHING_MONITORS
-		PrintFormatted(stream,"Monitor Implementation","Thin-locks");
+	#ifdef USE_SMALL_MONITORS
+		PrintFormatted(stream,"Monitor Implementation","small");
 	#else
-		PrintFormatted(stream,"Monitor Implementation","Standard");
+		PrintFormatted(stream,"Monitor Implementation","fast");
 	#endif
 	}
 
diff -Nur orig/pnet/engine/engine.h work.xxx/pnet/engine/engine.h
--- orig/pnet/engine/engine.h	2004-04-26 13:26:24.000000000 +1000
+++ work.new/pnet/engine/engine.h	2004-05-04 16:17:25.000000000 +1000
@@ -149,10 +149,11 @@
 	/* Hash table that contains all intern'ed strings within the system */
 	void		   *internHash;
 
-#ifdef USE_HASHING_MONITORS
+#ifdef USE_SMALL_MONITORS
 	/* Hash table that contains all monitors */
 	void			*monitorHash;
-	ILMutex		*monitorSystemLock;
+	ILMutex			*monitorSystemLock;
+	void			*monitorFreeList;
 #endif
 
 	/* Finalization context used by this process */
@@ -252,15 +253,12 @@
 	int				aborting;
 
 	/* System.Threading.Thread object */
-	ILObject *clrThread;
+	ILObject		*clrThread;
 
 	/* Marks this thread as a finalizer thread */
 	/* Finalizer threads are destroyed last */
 	int isFinalizerThread;
 
-	/* Free monitors list */
-	ILExecMonitor *freeMonitor;
-
 	/* Stack of call frames in use */
 	ILCallFrame	   *frameStack;
 	ILUInt32		numFrames;
@@ -269,7 +267,6 @@
 	/* Thread-static values for this thread */
 	void		  **threadStaticSlots;
 	ILUInt32		threadStaticSlotsUsed;
-
 };
 
 /*
@@ -319,28 +316,18 @@
 
 };
 
-typedef void * ILLockWord;
-
-struct _tagILExecMonitor
-{
-	ILWaitHandle *supportMonitor;
-	volatile ILInt32 waiters;
-	ILExecMonitor *next;
-	ILExecThread *owner;
-};
-
 /*
-*	Header of an object.
-*/
+ *	Header of an object.
+ */
 typedef struct _tagObjectHeader ILObjectHeader;
 
 struct _tagObjectHeader
 {
 	ILClassPrivate *classPrivate;
-#ifdef USE_HASHING_MONITORS
-	/* NOTHING */
+#ifdef USE_SMALL_MONITORS
+  	/* NOTHING */
 #else
-	ILLockWord lockWord;
+	void volatile	*monitor;
 #endif
 };
 
@@ -695,14 +682,14 @@
 void _ILHandleWaitResult(ILExecThread *thread, int result);
 
 /*
- *	Creates a monitor used by the execution engine.
+ * Initialse monitor.c's private data in the process structure.
  */
-ILExecMonitor *ILExecMonitorCreate(void);
+ILBool _ILMonitorProcessInit(ILExecProcess *process);
 
 /*
- *	Destroys a monitor used by the execution engine.
+ * Destroy monitor.c's private data in the process structure.
  */
-void ILExecMonitorDestroy(ILExecMonitor *monitor);
+void _ILMonitorProcessDestroy(ILExecProcess *process);
 
 #ifdef	__cplusplus
 };
diff -Nur orig/pnet/engine/heap.c work.xxx/pnet/engine/heap.c
--- orig/pnet/engine/heap.c	2003-07-16 08:17:33.000000000 +1000
+++ work.xxx/pnet/engine/heap.c	2004-05-04 18:40:50.000000000 +1000
@@ -207,7 +207,8 @@
 	}
 
 	/* Allocate memory from the heap */
-	ptr = ILGCAllocAtomic(size + IL_OBJECT_HEADER_SIZE);	
+	ptr = ILGCAllocAtomicHeader(size + IL_OBJECT_HEADER_SIZE, IL_OBJECT_HEADER_SIZE);	
+
 	if(!ptr)
 	{
 		/* Throw an "OutOfMemoryException" */
diff -Nur orig/pnet/engine/lib_defs.h work.xxx/pnet/engine/lib_defs.h
--- orig/pnet/engine/lib_defs.h	2003-07-05 18:30:56.000000000 +1000
+++ work.xxx/pnet/engine/lib_defs.h	2004-05-04 18:40:50.000000000 +1000
@@ -87,55 +87,6 @@
 */
 #define	GetObjectClass(obj)	((GetObjectClassPrivate((obj)))->classInfo)
 
-/* The GC guarantees that blocks are allocated on 4 byteboundaries
-    These MARK macros can be used to attach & query flags on each
-	monitor pointer. */
-
-#define IL_LW_MARKED(raw)	\
-	((((ILNativeUInt)(raw)) & 1) == 1)
-
-#define IL_LW_MARK(raw)	\
-	((ILLockWord)((((ILNativeUInt)(raw)) | 1)))
-
-#define IL_LW_UNMARK(raw)	\
-	((ILLockWord)((((ILNativeUInt)(raw)) & ~((ILNativeUInt)1))))
-
-#define GetObjectMonitor(thread, obj) \
-	((ILExecMonitor *)(IL_LW_UNMARK(GetObjectLockWord(thread, obj))))
-
-#ifdef USE_HASHING_MONITORS
-	
-	/*
-	 *	Gets a pointer to the WaitHandle object used by the object.
-	 */
-	ILLockWord CompareAndExchangeObjectLockWord
-		(ILExecThread *thread, ILObject *obj, ILLockWord value, ILLockWord comparand);
-
-	/*
-	 *	Gets the LockWord for the object.
-	 */
-	ILLockWord GetObjectLockWord(ILExecThread *thread, ILObject *obj);
-
-#else
-	/*
-	 *	Classic monitor tags are stored in the object header.
-	 */
-
-	#define GetObjectLockWord(thread, obj) \
-		(GetObjectHeader(obj)->lockWord)
-
-	#define SetObjectLockWord(thread, ob, value) \
-		GetObjectHeader(obj)->lockWord = value;
-
-	#define GetObjectLockWordPtr(thread, obj) \
-		(&(GetObjectLockWord(thread, obj)))
-
-	#define CompareAndExchangeObjectLockWord(thread, obj, value, comparand) \
-		(ILLockWord)((_IL_Interlocked_CompareExchange_RObjectObjectObject \
-			(thread, (ILObject **)GetObjectLockWordPtr(thread, obj), (ILObject *)value, (ILObject *)comparand)))
-
-#endif
-
 ILObject *_ILGetCurrentClrThread(ILExecThread *thread);
 
 /*
diff -Nur orig/pnet/engine/lib_thread.c work.xxx/pnet/engine/lib_thread.c
--- orig/pnet/engine/lib_thread.c	2004-05-04 17:37:10.000000000 +1000
+++ work.xxx/pnet/engine/lib_thread.c	2004-05-04 18:40:50.000000000 +1000
@@ -37,7 +37,7 @@
  * Comments on terminology:
  *
  * Support Thread:	Refers to an ILThread instance.
- * Engine Thread:		Refers to an ILExecThread instance.
+ * Engine Thread:	Refers to an ILExecThread instance.
  * CLR Thread:		Refers to a System.Threading.Thread instance. 
  */
 
@@ -47,605 +47,6 @@
 #define IL_CLR_WAIT_TIMEOUT (258L)
 
 /*
- * Maximum number of wait handles that can be processed at once.
- */
-#define	IL_MAX_WAIT_HANDLES		64
-
-/*
- * public static void Enter(Object obj);
- */
-void _IL_Monitor_Enter(ILExecThread *thread, ILObject *obj)
-{
-	_IL_Monitor_InternalTryEnter(thread, obj, IL_WAIT_INFINITE);	
-}
-
-/*
- * Spins until the object is unmarked and the current thread can mark it.
- */
-static IL_INLINE void _IL_ObjectLockword_WaitAndMark(ILExecThread *thread, volatile ILObject *obj)
-{
-	ILLockWord lockword;
-
-	for (;;)
-	{			
-		lockword = GetObjectLockWord(thread, obj);
-
-		if ((CompareAndExchangeObjectLockWord(thread, obj, IL_LW_MARK(lockword), 
-			IL_LW_UNMARK(lockword)) == IL_LW_UNMARK(lockword)))
-		{
-			break;
-		}
-
-		ILThreadSleep(0);
-	}
-}
-
-/*
- * Unmarks an object's lockword.
- */
-static IL_INLINE void _IL_ObjectLockword_Unmark(ILExecThread *thread, volatile ILObject *obj)
-{
-	ILLockWord lockword;
-
-	lockword = GetObjectLockWord(thread, obj);
-
-	SetObjectLockWord(thread, obj, IL_LW_UNMARK(lockword));
-}
-
-/*
- * Checks if the monitor is longer being used and returns it to the free list and
- * zeros the object's lockword.
- *
- * This method is only safe to call if you have exclusive acess to the object's
- * lockword.
- */
-static void _IL_Monitor_CheckAndReturnMonitorToFreeList(ILExecThread *thread, ILExecMonitor *monitor, volatile ILObject *obj)
-{
-	if (monitor == 0)
-	{
-		/* The monitor has already been claimed by another thread */
-		
-		return;
-	}
-
-	if(monitor->waiters == 0 && ILWaitMonitorCanClose(monitor->supportMonitor))
-	{
-		ILLockWord current;
-
-		/* Remove the monitor from the object if the object hasn't been assigned
-		      a new monitor */
-		current = CompareAndExchangeObjectLockWord(thread, obj, IL_LW_MARK(0), IL_LW_MARK(monitor));
-
-		if(current == IL_LW_MARK(monitor))
-		{
-			/* The object's monitor hasn't changed (or has changed and
-			   has become 'monitor' again) so no other thread claims
-			   this monitor as free */
-
-			/* Return the monitor to this thread's free list */
-
-			monitor->owner = 0;
-			monitor->next = thread->freeMonitor;
-			thread->freeMonitor = monitor;
-		}
-		else
-		{
-			/* The object's monitor has changed which means 'monitor'
-			   has already been claimed as as free by another thread */
-		}
-	}
-}
-
-/*
- * public static bool InternalTryEnter(Object obj, int timeout);
- *
- * The acquisition algorithm used is designed to be only require
- * a compare-and-exchange when the monitor is uncontested
- * (the most likely case).
- */
-ILBool _IL_Monitor_InternalTryEnter(ILExecThread *thread,
-		  	    		ILObject *objnv, ILInt32 timeout)
-{
-	int result;
-	ILLockWord lockword;
-	ILExecMonitor *monitor, *next;
-	volatile ILObject *obj;
-
-	obj = objnv;
-	
-	/* Make sure the object isn't null */
-	if (obj == 0)
-	{
-		ILExecThreadThrowArgNull(thread, "obj");
-
-		return 0;
-	}
-
-	/* Make sure the object isn't a value type */
-	if (ILType_IsValueType(GetObjectClass(obj)))
-	{
-		ILExecThreadThrowSystem(thread, "System.ArgumentException",
-																	"Arg_IsValueType");
-
-		return 0;
-	}
-
-	/* Make sure the timeout is within range */
-	if (timeout < -1)
-	{
-		ILExecThreadThrowArgRange(thread, "timeout", (const char *)0);
-
-		return 0;
-	}
-
-retry:
-
-	/* Get the lockword lock word */		
-	lockword = GetObjectLockWord(thread, obj);
-
-	if (lockword == 0)
-	{
-		/* There is no monitor installed for this object */
-
-		monitor = thread->freeMonitor;
-
-		if (monitor == NULL)
-		{
-			monitor = ILExecMonitorCreate();
-		}
-
-		next = monitor->next;
-		
-		/*	Try to install the new monitor. */
-		if (CompareAndExchangeObjectLockWord
-			(
-				thread,
-				obj,
-				IL_LW_MARK(monitor),
-				lockword
-			) == lockword)
-		{
-			/*
-			 * Succesfully installed the new monitor.
-			 * Calling FastClaim is faster than calling Enter cause we know that
-			 * no other thread can enter this monitor.
-		     */
-
-			result = ILWaitMonitorFastClaim(monitor->supportMonitor);
-
-			if (result != 0)
-			{
-				/* Dissociate the monitor from the object */
-				/* No need to do extensive checks (i.e. call
-				   CheckAndReturnMonitorToFreeList) since it's
-				   impossible for other threads to have managed
-				   to call Enter on this monitor */
-
-				SetObjectLockWord(thread, obj, 0);
-			
-				/* If the monitor is new, add it to the free list */
-				if (monitor != thread->freeMonitor)
-				{
-					monitor->next = thread->freeMonitor;
-					thread->freeMonitor = monitor;
-				}
-
-				_ILHandleWaitResult(thread, result);
-
-				return 0;
-			}
-
-			/* Remove the monitor from the free list */
-
-			thread->freeMonitor = next;
-
-			monitor->owner = thread;
-			
-			/* Finally allow other threads to enter the monitor */
-			_IL_ObjectLockword_Unmark(thread, obj);
-			
-			return 1;
-		}
-		else
-		{
-			/* Another thread managed to install a monitor first */
-
-			/* If the monitor is new, add it to the free list */
-			if (monitor != thread->freeMonitor)
-			{
-				monitor->next = thread->freeMonitor;
-				thread->freeMonitor = monitor;
-			}
-
-			goto retry;
-		}
-	}
-
-	/* Make sure noone is allowed to change the object's monitor */
-	_IL_ObjectLockword_WaitAndMark(thread, obj);
-
-	lockword = GetObjectLockWord(thread, obj);
-
-	/* If we get here then we know that no other thread can reassign the object's
-	       monitor */
-
-	monitor = IL_LW_UNMARK(lockword);
-	
-	if (monitor == 0 || monitor->owner == 0)
-	{
-		/* Some other thread owned the monitor but has released it
-		   since we last called GetObjectLockWord */
-
-		_IL_ObjectLockword_Unmark(thread, obj);
-		   
-		goto retry;
-	}
-
-	_IL_Interlocked_Increment_Ri(thread, (ILInt32 *)&monitor->waiters);
-
-	_IL_ObjectLockword_Unmark(thread, obj);
-
-	/* Try entering the monitor */	
-	result = ILWaitMonitorTryEnter(monitor->supportMonitor, timeout);
-	
-	/* Failed or timed out somehow */
-	if (result != 0)
-	{
-		/*
-		 * Decrement the waiters count and return the monitor to the free-list
-		 * if the object is no longer in any synchronized blocks.
-		 */
-		_IL_ObjectLockword_WaitAndMark(thread, obj);		
-		_IL_Interlocked_Decrement_Ri(thread, (ILInt32 *)&monitor->waiters);
-		_IL_Monitor_CheckAndReturnMonitorToFreeList(thread, monitor, obj);		
-		_IL_ObjectLockword_Unmark(thread, obj);
-
-		/* Handle ThreadAbort etc */		
-		_ILHandleWaitResult(thread, result);
-	}
-	else
-	{
-		monitor->owner = thread;
-		
-		_IL_Interlocked_Decrement_Ri(thread, (ILInt32 *)&monitor->waiters);
-	}
-
-	return result == 0;
-}
-
-/*
- * public static void Exit(Object obj);
- */
-void _IL_Monitor_Exit(ILExecThread *thread, ILObject *objnv)
-{
-	int result;
-	ILLockWord lockword;
-	ILExecMonitor *monitor;
-	volatile ILObject *obj;
-
-	obj = objnv;
-
-	/* Make sure obj isn't null */
-	if(obj == 0)
-	{
-		ILExecThreadThrowArgNull(thread, "obj");
-
-		return;
-	}
-
-	/* Make sure noone is allowed to change the object's monitor */
-	_IL_ObjectLockword_WaitAndMark(thread, obj);
-
-	/* Get the most up to date lock word.  It can't change from here on in */
-	lockword = GetObjectLockWord(thread, obj);
-
-	monitor = IL_LW_UNMARK(lockword);
-
-	/* Make sure the monitor is valid */
-	if (monitor == 0 || (monitor != 0 && monitor->owner != thread))
-	{
-		/* Hmm.  Can't call Monitor.Exit before Monitor.Enter */
-
-		_IL_ObjectLockword_Unmark(thread, obj);
-
-		ILExecThreadThrowSystem
-		(
-				thread,
-				"System.Threading.SynchronizationLockException",	
-				"Exception_ThreadNeedsLock"
-			);
-
-		return;
-	}
-	
-	if ((result = ILWaitMonitorSpeculativeLeave(monitor->supportMonitor)) > 0
-		/* Note: No need to check for aborts on call to leave */)
-	{
-		_IL_Monitor_CheckAndReturnMonitorToFreeList(thread, monitor, obj);
-				
-		/* There are waiters.  Unmark the lockword */		
-		_IL_ObjectLockword_Unmark(thread, obj);		
-
-		/* Notify waiting monitors */
-		ILWaitMonitorCompleteLeave(monitor->supportMonitor);
-	}
-	else
-	{
-		/* Unmark the lockword */
-		_IL_ObjectLockword_Unmark(thread, obj);
-
-		/* 
-		 * Support code doesn't think this thread owns the monitor
-		 * but we know it should cause engine level algorithms
-		 * should have ensured that it does.  This must be a VM
-		 * bug.
-		 */
-		ILExecThreadThrowSystem
-			(
-				thread,					
-				"System.ExecutionEngineException",
-				"Exception_UnexpectedEngineState"
-			);
-	}	
-}
-
-/*
- * public static bool InternalWait(Object obj, int timeout);
- */
-ILBool _IL_Monitor_InternalWait(ILExecThread *thread,
-				    ILObject *objnv, ILInt32 timeout)
-{
-	int result;
-	ILLockWord lockword;
-	ILExecMonitor *monitor;
-	volatile ILObject *obj;
-
-	obj = objnv;
-
-	/* Make sure obj isn't null */
-	if (obj == 0)
-	{		
-		ILExecThreadThrowArgNull(thread, "obj");
-
-		return 0;
-	}
-
-	_IL_ObjectLockword_WaitAndMark(thread, obj);
-	lockword = GetObjectLockWord(thread, obj);
-
-	monitor = IL_LW_UNMARK(lockword);
-
-	if (monitor == 0 || (monitor != 0 && monitor->owner != thread))
-	{
-		_IL_ObjectLockword_Unmark(thread, obj);
-
-		/* Object needs to own monitor */
-
-		ILExecThreadThrowSystem
-			(
-			thread,
-			"System.Threading.SynchronizationLockException",
-			"Exception_ThreadNeedsLock"
-			);
-
-		return 0;
-	}
-
-	/*
-	 * Inside the engine, monitor->waiters is used to prevent
-	 * _IL_Monitor_Exit from dissociating the monitor with the object.
-	 * However, in this method we know that no other thread can call 
-	 * _IL_Monitor_Exit before we call ILWaitMonitorWait because we know 
-	 * that we own the monitor.  However, once ILWaitMonitorWait has been
-	 * called, it releases the monitor so another thread theoretically could
-	 * exit it but it won't cause ILWaitMonitorCanClose knows that monitors
-	 * can't be closed (preventing monitor-object dissociiation in 
-	 * _IL_Monitor_Exit).  ILWaitMontiorCanClose knows this by using a 
-	 * different waiters count that is stored in the support monitor.
-	 *
-	 * What this all means is that we aren't required to increment/decrement
-	 * monitor->waiters to prevent premature monitor dissociation while we
-	 * "Wait".  For performance reasons, we won't do what isn't required.
-	 */
-
-	_IL_ObjectLockword_Unmark(thread, obj);
-
-	/* If we get here then we know that no other thread can reassign the object's
-	    monitor because we know we own the monitor */
-
-	switch (result = ILWaitMonitorWait(monitor->supportMonitor, timeout))
-	{
-	case 0:		
-
-		/* 
-		 * Support code doesn't think this thread owns the monitor
-		 * but we know it should cause engine level algorithms
-		 * should have ensured that it does.  This must be a VM
- 		 * bug.
-		 */
-
-		ILExecThreadThrowSystem
-			(
-				thread,
-				"System.ExecutionEngineException",
-				"Exception_UnexpectedEngineState"
-			);
-
-		
-		return 0;
-
-	case 1:
-
-		/* The current thread has exclusive access to the object's lockword */
-
-		monitor->owner = thread;
-
-		return 1;
-
-	case IL_WAIT_TIMEOUT:
-	case IL_WAIT_FAILED:
-
-		/* Timed out */
-	
-		return 0;
-
-	default:
-
-		/* Handle ThreadAbort etc */
-
-		_ILHandleWaitResult(thread, result);
-
-		return 0;
-	}
-}
-
-/*
- * public static void Pulse(Object obj);
- */
-void _IL_Monitor_Pulse(ILExecThread *thread, ILObject *obj)
-{
-	int result;
-	ILExecMonitor *monitor;
-
-	if(obj == 0)
-	{
-		ILExecThreadThrowArgNull(thread, "obj");
-	}
-
-	_IL_ObjectLockword_WaitAndMark(thread, obj);
-	
-	monitor = GetObjectMonitor(thread, obj);
-
-	if (monitor == 0 || (monitor != 0 && monitor->owner != thread))
-	{
-		/* Object needs to own monitor */
-
-		_IL_ObjectLockword_Unmark(thread, obj);
-
-		ILExecThreadThrowSystem
-			(
-				thread,
-				"System.Threading.SynchronizationLockException",
-				"Exception_ThreadNeedsLock"
-			);
-
-		return;
-	}
-	
-	_IL_ObjectLockword_Unmark(thread, obj);
-
-	result = ILWaitMonitorPulse(monitor->supportMonitor);
-	
-	switch (result)
-	{
-	case 0:
-
-		/* 
-		* Support code doesn't think this thread owns the monitor
-		* but we know it should cause engine level algorithms
-		* should have ensured that it does.  This must be a VM
-		* bug.
-		*/
-
-		ILExecThreadThrowSystem
-			(
-				thread,
-				"System.ExecutionEngineException",
-				"Exception_UnexpectedEngineState"
-			);
-
-		return;
-
-	case 1:
-
-		/* Successfully pulsed */
-		
-		return;
-
-	default:
-
-		/* Handle ThreadAbort etc */
-
-		_ILHandleWaitResult(thread, result);
-
-		return;
-	}
-}
-
-/*
- * public static void PulseAll(Object obj);
- */
-void _IL_Monitor_PulseAll(ILExecThread *thread, ILObject *obj)
-{
-	int result;
-	ILExecMonitor *monitor;
-
-	if(obj == 0)
-	{
-		ILExecThreadThrowArgNull(thread, "obj");
-	}
-
-	_IL_ObjectLockword_WaitAndMark(thread, obj);
-
-	monitor = GetObjectMonitor(thread, obj);
-
-	if (monitor == 0 || (monitor != 0 && monitor->owner != thread))
-	{
-		/* Object needs to own monitor */
-
-		_IL_ObjectLockword_Unmark(thread, obj);
-
-		ILExecThreadThrowSystem
-			(
-				thread,
-				"System.Threading.SynchronizationLockException",
-				"Exception_ThreadNeedsLock"
-			);
-
-		return;
-	}
-
-	_IL_ObjectLockword_Unmark(thread, obj);
-
-	result = ILWaitMonitorPulseAll(monitor->supportMonitor);
-
-	switch (result)
-	{ 
-	case 0:
-
-		/* 
-		 * Support code doesn't think this thread owns the monitor
-		 * but we know it should cause engine level algorithms
-		 * should have ensured that it does.  This must be a VM
-		 * bug.
-		 */
-
-		ILExecThreadThrowSystem
-				(
-				thread,
-				"System.ExecutionEngineException",
-				"Exception_UnexpectedEngineState"
-				);
-
-		return;
-
-	case 1:
-
-		/* Successfully pulsed */
-
-		return;
-
-	default:
-
-		/* Handle ThreadAbort etc */
-
-		_ILHandleWaitResult(thread, result);
-
-		return;
-	}
-}
-
-/*
  * public static int CompareExchange(ref int location1, int value,
  *									 int comparand);
  */
@@ -696,14 +97,7 @@
 						 ILObject *value,
 						 ILObject *comparand)
 {
-	ILObject *orig;
-	ILThreadAtomicStart();
-	if((orig = *location1) == comparand)
-	{
-		*location1 = value;
-	}
-	ILThreadAtomicEnd();
-	return orig;
+	return ILThreadCompareAndSwapPtr(location1, value, comparand);
 }
 
 /*
diff -Nur orig/pnet/engine/monitor.c work.xxx/pnet/engine/monitor.c
--- orig/pnet/engine/monitor.c	2004-05-03 02:40:22.000000000 +1000
+++ work/pnet/engine/monitor.c	2004-05-05 18:06:28.000000000 +1000
@@ -4,6 +4,7 @@
  * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
  *
  * Authors:  Thong Nguyen (tum@veridicus.com)
+ *           Russell Stuart (russell-savannah@stuart.id.au)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,250 +20,778 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
 #include "engine.h"
 #include "lib_defs.h"
 
+/*
+ * Monitors come is two varieties: fast at small.  The type used is
+ * determined by USE_SMALL_MONITORS #define.  If defined the monitors
+ * are small, otherwise they are fast.
+ *
+ * The difference between the two is in their memory allocation and
+ * tracking.  When fast monitors are used, each object contains a
+ * monitor pointer.  When the object's monitor is first referenced
+ * the monitor is created and a pointer to it put in this slot.  The
+ * monitor is garbage collected when the object dies.
+ *
+ * Small monitors don't require require an extra slot in every object:
+ * that is why they are small.  The pointer to them is stored in a global
+ * hash table.  The index to the hash table is the objects pointer.
+ * Small monitors are only associated with the object while the object
+ * is locked or has waiters.  Thereafter they are returned to a free
+ * list for re-use.  The down side is that aquiring and releasing a
+ * monitor requires a global lock, which can be slow.
+ *
+ * This code assumes a java like memory model.  When the underlying mutex
+ * is locked, the CPU's cache is assumed to be invalided, thus forcing
+ * everything to be re-read from main memory.  When the underlying mutex
+ * is unlocked the CPU's cache is assumed to be flushed, ie everything
+ * that has changed is written to main memory where other CPU's can
+ * see it - when they do their next lock.
+ */
+
 #ifdef	__cplusplus
 extern	"C" {
 #endif
 
-ILExecMonitor *ILExecMonitorCreate(void)
-{
-	ILExecMonitor *monitor;
 
-	/* Allocate memory for the ILExecMonitor */
-	if((monitor = (ILExecMonitor *)ILMalloc(sizeof(ILExecMonitor))) == 0)
-	{
-		return 0;
-	}
+typedef struct _tagMonitor Monitor;
 
-	/* Allocate memory for the wait monitor */
-	if((monitor->supportMonitor = ILWaitMonitorCreate()) == 0)
-	{
-		ILFree(monitor);
+#if	USE_SMALL_MONITORS
 
-		return 0;
-	}
-
-	monitor->waiters = 0;
-	monitor->next = 0;
-	monitor->owner = 0;
-
-	return monitor;
-}
-
-void ILExecMonitorDestroy(ILExecMonitor *monitor)
+struct _tagMonitor
 {
-	ILWaitHandleClose(monitor->supportMonitor);
-
-	ILFree(monitor);
-}
-
-#ifdef USE_HASHING_MONITORS
+	ILWaitHandle	*waitHandle;
+	ILMutex			*mutex;
+	ILInt32			enterCount;
+	ILExecThread	*waitHandleOwner;
+	ILObject		*object;
+	Monitor			*next;
+};
 
 #define DEFAULT_HASHTABLE_SIZE		(523)
 
 /*
- *	An entry in the monitor Hashtable.
+ * Do all initialisation required on the process structure.
  */
-typedef struct _tagILMonitorEntry ILMonitorEntry;
-struct _tagILMonitorEntry
+ILBool _ILMonitorProcessInit(ILExecProcess *process)
 {
-	ILObject *obj;
-	ILLockWord lockWord;
-	ILMonitorEntry *next;
-};
+	process->monitorProcessMutex = ILMutexCreate();
+	process->monitorHash = ILMalloc(sizeof(Monitor) * DEFAULT_HASHTABLE_SIZE);
+	return process->monitorProcessMutex != 0 && process->monitorHash != 0;
+}
 
 /*
- *	Gets a pointer to the WaitHandle object used by the object.
+ * Do all clean up required on the process structure.
  */
-static ILLockWord *GetObjectLockWordPtr(ILExecThread *thread, ILObject *obj)
+void _ILMonitorProcessDestroy(ILExecProcess *process)
 {
-	ILInt32 x;
-	ILMonitorEntry **table, *entry, *ghost;
-
-	ILMutexLock(thread->process->monitorSystemLock);
-
-	table = thread->process->monitorHash;
-
-	if (table == 0)
+	if (process->monitorHash != 0)
 	{
-		/* Create the monitor hashtable */
-
-		table = (ILMonitorEntry **)ILGCAlloc(sizeof(ILMonitorEntry *)
-																* DEFAULT_HASHTABLE_SIZE);
-
-		if (table == 0)
-		{
-			ILExecThreadThrowOutOfMemory(thread);
-
-			ILMutexUnlock(thread->process->monitorSystemLock);
-
-			return 0;
-		}
-
-		thread->process->monitorHash = table;
+		ILFree(process->monitorHash);
+		process->monitorHash = 0;
+	}
+	if (process->monitorProcessMutex != 0)
+	{
+		ILMutexDestroy(process->monitorProcessMutex);
+		process->monitorProcessMutex = 0;
 	}
+}
 
-	/* Get the hashtable index */
+/*
+ * Get & lock the monitor associated with an object, optionally
+ * creating it if it doesn't exist.  This must be matched by
+ * a call to MonitorRelease().
+ */
+static Monitor *MonitorAquire(ILExecThread *thread, ILObject *object, ILBool create)
+{
+	Monitor*  monitor;
+	Monitor** ptr;
 
-	x = (ILInt32)obj;
-	x = ((x >> 16) ^ (x & 0xffff)) % DEFAULT_HASHTABLE_SIZE;
-	
-	entry = table[x];
-	
-	if (entry == 0)
+	ILMutexLock(thread->process->monitorProcessMutex);
+	ptr = FindMonitor(thread->process, object);
+	monitor = *ptr;
+	if (monitor == 0 || monitor->object == 0)
 	{
-		/* The bucket is empty */
-		/* Start a new bucket by creating a new hashtable entry */
-
-		if ((entry = (ILMonitorEntry *)ILGCAlloc(sizeof(ILMonitorEntry))) == 0)
+	  	/*
+		 * The hash table doesn't contain a monitor for this object.
+		 */
+		if (!create)
 		{
-			ILExecThreadThrowOutOfMemory(thread);
-
-			ILMutexUnlock(thread->process->monitorSystemLock);
-
+			ILMutexUnlock(thread->process->monitorProcessMutex);
 			return 0;
 		}
-
-		entry->lockWord = 0;
-		entry->obj = obj;
-		entry->next = 0;
-		table[x] = entry;
-
-		ILGCRegisterGeneralWeak(&entry->obj, obj);
-
-		ILMutexUnlock(thread->process->monitorSystemLock);
-
-		return &entry->lockWord;
-	}
-	else
-	{
-		/* The bucket isn't empty.  Search for the right entry. */
-
-		ghost = 0;
-
-		for (;;)
+		/*
+		 * If the monitor returned points to an object that has been reclaimed
+		 * by the garbage collector, then reuse it.  Otherwise we must
+		 * create a new monitor.
+		 */
+		if (monitor == 0)
 		{
-			if (entry->obj == obj)
+			/*
+			 * If the are monitors on the global free list reuse them,
+			 * otherwise create a new one.
+			 */
+			if (monitorFreeList != 0)
 			{
-				/* Entry was found.  Return it */
-
-				ILMutexUnlock(thread->process->monitorSystemLock);
-
-				return &entry->lockWord;
+				monitor = monitorFreeList;
+				monitorFreeList = monitor->next;
 			}
-			else if (entry->obj == 0)
+			else
 			{
-				/* Found an entry pointing to a dead object */
-
-				if (ghost == 0)
+				monitor = (Monitor *)ILMalloc(*monitor);
+				if (monitor == 0)
 				{
-					/* The ghost will be GCed so no need to free it if we don't 
-										end up using it */
-
-					ghost = entry;
-
-					ghost->obj = obj;
-					ghost->next =	 0;					
+					ILMutexUnlock(thread->process->monitorProcessMutex);
+					return 0;
+				}
+				monitor->waitHandle = ILWaitMonitorCreate();
+				if (monitor->waitHandle == 0)
+				{
+					ILFree(monitor);
+					ILMutexUnlock(thread->process->monitorProcessMutex);
+					return 0;
 				}
 			}
-			
-			entry = entry->next;
-
-			if (entry == 0)
-			{
-				/* No entry was found */
-
-				if (ghost == 0)
-				{					
-					/* No ghost found.  Create a whole new entry. */
-
-					if ((entry = (ILMonitorEntry *)ILGCAlloc(sizeof(ILMonitorEntry))) == 0)
-					{
-						ILExecThreadThrowOutOfMemory(thread);
-
-						ILMutexUnlock(thread->process->monitorSystemLock);
+			/*
+			 * Link the new monitor into the hash table list.
+			 */
+			monitor->next = *ptr;
+			*ptr = monitor;
+		}
+		monitor->object = object;
+		/*
+		 * Make this pointer "weak", so the garbage collector will
+		 * set it zero if it reclaims the object.
+		 */
+		ILGCRegisterGeneralWeak(&monitor->object, object);
+	}
+	ILMutexLock(monitor->mutex);
+	ILMutexUnlock(thread->process->monitorProcessMutex);
+	return monitor;
+}
 
-						return 0;
-					}
+/*
+ * Release a monitor, and free it if it is not being used.  This must match
+ * a prior call to MonitorAquire().
+ *
+ * The parameter enterAdjust reflects whether the thread is entering or
+ * leaving a Monitor.Enter()..Monitor.Exit() block.  The term "entering"
+ * includes "about to wait upon entering", and the term "leaving" includes
+ * the said wait on entering failing (eg timeout).  If entering, enterAdjust
+ * must be 1, if leaving it must be -1, if no change it must be 0.
+ */
+static void MonitorRelease(Monitor *monitor, int enterAdjust)
+{
+	Monitor **entry;
+	/*
+	 * If somebody is still between a Monitor.Enter() .. Monitor.Exit(),
+	 * just return.  The monitor is still in use.
+	 */
+	monitor->enterCount += enterAdjust;
+	if (monitor->enterCount != 0)
+	{
+		ILMutexUnlock(monitor->mutex);
+		return;
+	}
+	/*
+	 * Since nobody is in a Monitor.Enter() .. Monitor.Exit() block the
+	 * monitor is no longer is use.  (This implies nobody can be waiting
+	 * on it either).
+	 */
+	ILMutexLock(&monitorGlobalLock);
+	entry = FindMonitor(monitor->object);
+	*entry = monitor->next;
+	monitor->next = monitorFreeList;
+	monitorFreeList = monitor;
+	ILMutexUnlock((*monitor)->mutex);
+	ILMutexUnlock(&monitorGlobalLock);
+}
 
-					entry->lockWord = 0;
-				}
-				else
-				{
-					/* We found a ghost!  Use the ghost */
+/*
+ * Find a monitor in the hash table.  Returns one of:
+ *   - if the object is in the table, a reference to the monitor
+ *     for the passed object.
+ *   - if the object is not in the table, 0, OR
+ *   - if the object is not in the table an unused monitor whose
+ *     monitor->object is 0.
+ */
+static Monitor** FindMonitor(ILObject *object)
+{
+	Monitor** free;
+	Monitor** monitor;
+	ILNativeInt hash;
+
+	hash = (ILNativeInt)obj;
+	hash = (hash >> 32) ^ hash;
+	hash = (hash >> 16) ^ hash;
+	monitor = &process->monitorHash[hash % DEFAULT_HASHTABLE_SIZE];
+	/*
+	 * As we travel along the list, look for an unused monitor - ie one
+	 * whose object has been reclaimed by the garbage collector and
+	 * consequently has the weak reference set to 0.  If we find one and
+	 * don't find the monitor we can re-use it.
+	 */
+	free = 0;
+	while (*monitor != 0 && (*monitor)->object != object)
+	{
+		if ((*monitor)->object == 0)
+			free = monitor;
+	}
+	if (*monitor != 0 || free == 0)
+		return monitor;
+	return free;
+}
 
-					entry = ghost;
-				}
+#else
 
-				/* Setup the new entry */
+struct _tagMonitor
+{
+	ILWaitHandle	*waitHandle;
+	ILMutex			*mutex;
+	ILInt32			enterCount;
+	ILExecThread	*waitHandleOwner;
+};
 
-				entry->obj = obj;
-				entry->next = table[x];
-				table[x] = entry;
+/*
+ * Do all initialisation required on the process structure.
+ */
+ILBool _ILMonitorProcessInit(ILExecProcess *process)
+{
+	return 1;
+}
 
-				/* Make the entry's obj pointer weak and let it be set to 0 
-								if the object is collected */
-				ILGCRegisterGeneralWeak(&entry->obj, obj);
+/*
+ * Do all clean up required on the process structure.
+ */
+void _ILMonitorProcessDestroy(ILExecProcess *process)
+{
+}
 
-				ILMutexUnlock(thread->process->monitorSystemLock);
+/*
+ * The monitor has been garbage collected.
+ */
+static void MonitorFinalise(void *block, void *data)
+{
+	Monitor *monitor = (Monitor *)block;
+	/*
+	 * This lock is done to invalidate the cache.
+	 */
+	ILMutexLock(monitor->mutex);
+	if (monitor->waitHandle != 0)
+		ILWaitHandleClose(monitor->waitHandle);
+	ILMutexUnlock(monitor->mutex);
+	ILMutexDestroy(monitor->mutex);
+}
 
-				return &entry->lockWord;
-			}
+/*
+ * Get & lock the monitor associated with an object, optionally
+ * creating it if it doesn't exist.  This must be matched by
+ * a call to MonitorRelease().
+ */
+static Monitor *MonitorAquire(ILObject *object, ILBool create)
+{
+	ILObjectHeader *objectHeader = GetObjectHeader(object);
+	Monitor* monitor;
+	Monitor* currentMonitor;
+
+retry:
+	monitor = (Monitor*)objectHeader->monitor;
+	if (monitor != 0)
+	{
+		/*
+		 * We can see the monitor pointer in the object, but there is no
+		 * guarentee the thread can see the body of the monitor - there
+		 * may be old words in the CPU's cache.  This lock, besides locking
+		 * the monitor, ensures the body of the monitor is valid in the 
+		 * CPU's cache.
+		 */
+		ILMutexLock(monitor->mutex);
+		/*
+		 * Has MonitorRelease() detached the monitor from the object?
+		 * If so, try again.
+		 *
+		 * This can't happen right now.  Monitors are always detached
+		 * when they are garbage collected.  But it did in a earlier
+		 * version.
+		 */
+		if (objectHeader->monitor != monitor)
+		{
+			ILMutexUnlock(monitor->mutex);
+			goto retry;
 		}
+		return monitor;
 	}
-
-	ILMutexUnlock(thread->process->monitorSystemLock);
-	
-	return 0;
+	/*
+	 * The object does not _appear_ to have a monitor attached.  At this
+	 * stage we can't be entirely sure - it may be that our cache is out
+	 * of date.  It may remain that way forever, meaning the thread will
+	 * never see the monitor, unless the cache is invalidated.  Note: this
+	 * will not be a problem on i386, as it i386 has hardware bus snooping.
+	 * It will be a problem on other architectures.
+	 *
+	 * Which is why the odd piece of code appears below.  The mutex is
+	 * created and locked - even though we may not need it, because a
+	 * side effect of locking it is to invalidate the cache.
+	 */
+	ILMutex *mutex = ILMutexCreate();
+	ILMutexLock(mutex);
+	monitor = (Monitor*)objectHeader->monitor;
+	if (monitor != 0)
+	{
+		/*
+		 * Well, well.  The monitor existed after all!
+		 */
+		ILMutexUnlock(mutex);
+		ILMutexDestroy(mutex);
+		ILMutexLock(monitor->mutex);
+		/*
+		 * Same code as above - handle MonitorRelease() detaching monitor
+		 * from the object.
+		 */
+		if (objectHeader->monitor != monitor)
+		{
+			ILMutexUnlock(monitor->mutex);
+			goto retry;
+		}
+		return monitor;
+	}
+	/*
+	 * There definitely isn't a monitor - if we aren't supposed to
+	 * create one get out of here.
+	 */
+	if (!create)
+	{
+		ILMutexUnlock(mutex);
+		ILMutexDestroy(mutex);
+		return 0;
+	}
+	/*
+	 * Create a new monitor.
+	 */
+	monitor = ILGCAlloc(sizeof(*monitor));
+	if (monitor == 0)
+	{
+		ILMutexUnlock(mutex);
+		ILMutexDestroy(mutex);
+		return 0;
+	}
+	ILGCRegisterFinalizer(monitor, MonitorFinalise, 0);
+	monitor->mutex = mutex;
+	monitor->waitHandle = ILWaitMonitorCreate();
+	if (monitor->waitHandle == 0)
+	{
+		/*
+		 * Out of memory - let the garbage collector clean up.
+		 */
+		ILMutexUnlock(monitor->mutex);
+		return 0;
+	}
+	/*
+	 * Attach the monitor to the object.  This is an atomic operation.
+	 * One of two things will happen.
+	 *   a.  The object->monitor word is still 0, in which case
+	 *       our newly created monitor will be attached and returned, or
+	 *   b.  Some other thread has attached a monitor while we were
+	 *       stuffing around in here, in which case his monitor is
+	 *       returned.
+	 */
+	currentMonitor = (Monitor*)ILThreadCompareAndSwapPtr(
+			(void**)&objectHeader->monitor, monitor, 0);
+	if (currentMonitor == 0)
+	{
+		return monitor;					/* Our monitor wins! */
+	}
+	/*
+	 * Somebody snuck in before us.  Use his monitor.  The one we created
+	 * will be garbage collected.
+	 */
+	ILMutexUnlock(monitor->mutex);
+	ILMutexLock(currentMonitor->mutex);
+	/*
+	 * Same code as above, again - handle MonitorRelease() detaching monitor
+	 * from the object.
+	 */
+	if (objectHeader->monitor != currentMonitor)
+	{
+		ILMutexUnlock(currentMonitor->mutex);
+		goto retry;
+	}
+	return currentMonitor;
 }
 
 /*
- *	Implementation of GetObjectLockWord using hashtables.
+ * Release the monitor.
+ *
+ * The parameter enterAdjust reflects whether the thread is entering or
+ * leaving a Monitor.Enter()..Monitor.Exit() block.  The term "entering"
+ * includes "about to wait upon entering", and the term "leaving" includes
+ * the said wait on entering failing (eg timeout).  If entering, enterAdjust
+ * must be 1, if leaving it must be -1, if no change it must be 0.
  */
-ILLockWord	GetObjectLockWord(ILExecThread *thread, ILObject *obj)
+static void MonitorRelease(Monitor *monitor, int enterAdjust)
 {
-	return *GetObjectLockWordPtr(thread, obj);
+	/*
+	 * If somebody is still between a Monitor.Enter() .. Monitor.Exit(),
+	 * just return.  The monitor is still in use.
+	 */
+	monitor->enterCount += enterAdjust;
+	if (monitor->enterCount != 0)
+	{
+		ILMutexUnlock(monitor->mutex);
+		return;
+	}
+	/*
+	 * The monitor could be detached from the object here - ie just before
+	 * it is unlocked.  It isn't because on most architectures
+	 * ILThreadCompareAndSwapPtr() aquires a global lock, which is a
+	 * potential bottle neck.  Detaching the monitor would mean we hit
+	 * that bottle neck much more often.  Insteat the garbage collector
+	 * is used to detect when the monitor is no longer in use because
+	 * its associated object has died, and it is freed then.
+	 */
+	ILMutexUnlock(monitor->mutex);
 }
+#endif
 
 /*
-*	Implementation of SetObjectLockWord using hashtables.
-*/
-void SetObjectLockWord(ILExecThread *thread, ILObject *obj, value)
+ * public static void Enter(Object obj);
+ */
+void _IL_Monitor_Enter(ILExecThread *thread, ILObject *obj)
 {
-	*GetObjectLockWordPtr(thread, obj) = value;
+	_IL_Monitor_InternalTryEnter(thread, obj, IL_WAIT_INFINITE);	
 }
 
-
 /*
- *	Implementation of CompareAndExchangeObjectLockWord using hashtables.
+ * public static bool InternalTryEnter(Object obj, int timeout);
  */
-ILLockWord CompareAndExchangeObjectLockWord(ILExecThread *thread, 
-							ILObject *obj, ILLockWord value, ILLockWord comparand)
+ILBool _IL_Monitor_InternalTryEnter(ILExecThread *thread,
+						ILObject *obj, ILInt32 timeout)
 {
-	ILLockWord oldValue;
-	ILLockWord *lockWordPtr;
+	Monitor *monitor;
+	int result;
+	
+	/*
+	 * Make sure the object isn't null.
+	 */
+	if (obj == 0)
+	{
+		ILExecThreadThrowArgNull(thread, "obj");
+		return 0;
+	}
+	/*
+	 * Make sure the object isn't a value type.
+	 */
+	if (ILType_IsValueType(GetObjectClass(obj)))
+	{
+		ILExecThreadThrowSystem(
+			thread, "System.ArgumentException", "Arg_IsValueType");
+		return 0;
+	}
+	/*
+	 * Make sure the timeout is within range.
+	 */
+	if (timeout < -1)
+	{
+		ILExecThreadThrowArgRange(thread, "timeout", (const char *)0);
+		return 0;
+	}
+	/*
+	 * Arguments are OK.
+	 */
+	monitor = MonitorAquire(obj, 1);
+	/*
+	 * Did we run out of memory?
+	 */
+	if (monitor == 0)
+	{
+		ILExecThreadThrowOutOfMemory(thread);
+		return 0;
+	}
+	/*
+	 * End of checks.  Now do the wait.
+	 */
+	MonitorRelease(monitor, +1);
+	result = ILWaitMonitorTryEnter(monitor->waitHandle, timeout);
+	/*
+	 * If that worked we now own the monitor. monitor->waitHandleOwner is
+	 * guarded by the waitHandle, not by monitor->mutex, so there is no
+	 * race here.
+	 */
+	if (result == 0)
+	{
+		monitor->waitHandleOwner = thread;
+		return 1;
+	}
+	/*
+	 * Timeout.   We didn't get the lock, so decrement the enterCount as
+	 * the thread is no longer in the Enter()...Exit() block.
+	 *
+	 * Ugly, but on the typical "lock (...) ..." path.
+	 *
+	 * Note: This code is not used for fast monitors, as they don't
+	 * currently use the enterCount.  But it is needed for the small
+	 * monitors.
+	 */
+	MonitorRelease(MonitorAquire(obj, 0), -1);
+	_ILHandleWaitResult(thread, result);
+	return 0;
+}
 
-	/* Lockdown the monitor hashtable */
-	ILMutexLock(thread->process->monitorSystemLock);
+/*
+ * public static void Exit(Object obj);
+ */
+void _IL_Monitor_Exit(ILExecThread *thread, ILObject *obj)
+{
+	int result;
+	Monitor *monitor;
 	
-	lockWordPtr = GetObjectLockWordPtr(thread, obj);
+	/*
+	 * Make sure obj isn't null.
+	 */
+	if (obj == 0)
+	{
+		ILExecThreadThrowArgNull(thread, "obj");
+		return;
+	}
+	/*
+	 * Get the monitor.
+	 */
+	monitor = MonitorAquire(obj, 0);
+	/*
+	 * Verify there has been a prior matching call to Enter.
+	 */
+	if (monitor == 0 || monitor->waitHandleOwner != thread)
+	{
+		if (monitor != 0)
+			MonitorRelease(monitor, 0);
+		ILExecThreadThrowSystem(
+			thread,
+			"System.Threading.SynchronizationLockException",	
+			"Exception_ThreadNeedsLock");
+		return;
+	}
+	/*
+	 * The guard lock for monitor->waitHandleOwner is NOT the lock
+	 * maintained by MonitorAquire.  It is the lock maintained by
+	 * monitor->waitHandle.  Ergo, monitor->waitHandleOwner can only
+	 * be changed while the thread owns the monitor.  We will know
+	 * whether we continue to own the lock after ILWaitMutexRelease
+	 * is called, but since it is possible that this thread won't
+	 * be the monitor waitHandleOwner when it returns
+	 * monitor->waitHandleOwner must be set to 0 now, because we
+	 * can't change it later if the thread no longer own
+	 * monitor->waitHandle.
+	 */
+	monitor->waitHandleOwner = 0;
+	/*
+	 * Do the leave.
+	 */
+	result = ILWaitMutexRelease(monitor->waitHandle);
+	/*
+	 * If we didn't own the monitor chuck an exception.
+	 *
+	 * This should NEVER happen.  This thread was verified to own the monitor
+	 * above.
+	 */
+	if (result <= 0)
+	{
+		MonitorRelease(monitor, 0);
+		ILExecThreadThrowSystem(
+			thread,					
+			"System.Threading.SynchronizationLockException",
+			"Exception_ThreadNeedsLock");
+		return;
+	}
+	/*
+	 * Decrement the enterCount.
+	 */
+	MonitorRelease(monitor, -1);
+	/*
+	 * If this thread still owns the monitor undo the assignment above.
+	 * Again there is no race condition here as monitor->waitHandleOwner
+	 * is guarded by monitor->waitHandle, not monitor->mutex.
+	 */
+	if (result == IL_WAIT_LEAVE_STILL_OWNS)
+		monitor->waitHandleOwner = thread;
+}
+
+/*
+ * public static bool InternalWait(Object obj, int timeout);
+ */
+ILBool _IL_Monitor_InternalWait(ILExecThread *thread,
+					ILObject *obj, ILInt32 timeout)
+{
+	int result;
+	Monitor *monitor;
 
-	/* Do the compare & exchange */
-	if ((oldValue = *lockWordPtr ) == comparand)
+	/*
+	 * Make sure obj isn't null.
+	 */
+	if (obj == 0)
+	{
+		ILExecThreadThrowArgNull(thread, "obj");
+		return 0;
+	}
+	/*
+	 * See if we own the monitor.  Can't wait on the monitor if we don't
+	 * own it.
+	 *
+	 * Note: this piece of code is the reason montor->waitHandleOwner exists.
+	 * ILWaitMonitorWait will verify this thread owns the monitor, but
+	 * by then it is too late.  If this thread doesn't own the monitor
+	 * it could literally disappear before ILWaitMonitorWait is called.
+	 */
+	monitor = MonitorAquire(obj, 0);
+	if (monitor == 0 || monitor->waitHandleOwner != thread)
+	{
+		if (monitor != 0)
+			MonitorRelease(monitor, 0);
+		ILExecThreadThrowSystem(
+			thread,
+			"System.Threading.SynchronizationLockException",
+			"Exception_ThreadNeedsLock");
+		return 0;
+	}
+	/*
+	 * This thread relinquishes the monitor during the wait.
+	 */
+	monitor->waitHandleOwner = 0;
+	/*
+	 * Do the wait.
+	 */
+	MonitorRelease(monitor, 0);
+	result = ILWaitMonitorWait(monitor->waitHandle, timeout);
+	switch (result)
 	{
-		*lockWordPtr  = value;
+	case 0:
+		/*
+		 * We didn't own the monitor.
+		 *
+		 * This should NEVER happen.  The thread was verified to own the
+		 * monitor above.
+		 */
+		ILExecThreadThrowSystem(
+			thread,
+			"System.Threading.SynchronizationLockException",
+			"Exception_ThreadNeedsLock");
+		return 0;
+	case 1:
+		/*
+		 * Successfully waited.  This thread now owns monitor->waitHandle
+		 * again.
+		 */
+		monitor->waitHandleOwner = thread;
+		return 1;
+	case IL_WAIT_TIMEOUT:
+		/*
+		 * Timed out.  This thread now owns monitor->waitHandle again.
+		 */
+		monitor->waitHandleOwner = thread;
+		return 0;
+	case IL_WAIT_INTERRUPTED:
+	case IL_WAIT_ABORTED:
+		/*
+		 * Abort or Interrupt.
+		 */
+		monitor->waitHandleOwner = thread;
+		_ILHandleWaitResult(thread, result);
+		return 0;
+	default:
+	case IL_WAIT_FAILED:
+		/*
+		 * Not possible, I think.  Only seems to happen if a new wakeup
+		 * object has to be allocated and there is not enough memory.
+		 */
+		return 0;
 	}
+}
+
+/*
+ * Internal version of Pulse.
+ */
+static void MonitorPulseInternal(ILExecThread *thread, ILObject *obj, ILBool all)
+{
+	int result;
+	Monitor *monitor;
 
-	/* Unlock the monitor hashtable */
-	ILMutexUnlock(thread->process->monitorSystemLock);
+	/*
+	 * Object null?
+	 */
+	if (obj == 0)
+	{
+		ILExecThreadThrowArgNull(thread, "obj");
+		return;
+	}
+	/*
+	 * Get the monitor.
+	 */
+	monitor = MonitorAquire(obj, 0);
+	/*
+	 * We must own the monitor.
+	 *
+	 * Note: this piece of code is the reason montor->waitHandleOwner exists.
+	 * ILWaitMonitorWait will verify this thread owns the monitor, but
+	 * by then it is too late.  If this thread doesn't own the monitor
+	 * it could literally disappear before ILWaitMonitorWait is called.
+	 */
+	if (monitor == 0 || monitor->waitHandleOwner != thread)
+	{
+		if (monitor != 0)
+			MonitorRelease(monitor, 0);
+		ILExecThreadThrowSystem(
+			thread,
+			"System.Threading.SynchronizationLockException",
+			"Exception_ThreadNeedsLock");
+		return;
+	}
+	/*
+	 * Pulse the monitor.
+	 */
+	MonitorRelease(monitor, 0);
+	result = ILWaitMonitorPulse(monitor->waitHandle, all);
+	switch (result)
+	{
+	case 0:
+		/*
+		 * Thread doesn't currently own lock.
+		 *
+		 * This should NEVER happen.  The thread was verified to own the
+		 * monitor above.
+		 */
+		ILExecThreadThrowSystem(
+			thread,
+			"System.Threading.SynchronizationLockException",
+			"Exception_ThreadNeedsLock");
+		return;
+	case 1:
+		/*
+		 * Successfully pulsed.
+		 */
+		return;
+	default:
+		/*
+		 * There are no other returns.  This should never be executed.
+		 */
+		return;
+	}
+}
 
-	return oldValue;
+/*
+ * public static void Pulse(Object obj);
+ */
+void _IL_Monitor_Pulse(ILExecThread *thread, ILObject *obj)
+{
+	MonitorPulseInternal(thread, obj, 0);
 }
 
-#endif
+/*
+ * public static void PulseAll(Object obj);
+ */
+void _IL_Monitor_PulseAll(ILExecThread *thread, ILObject *obj)
+{
+	MonitorPulseInternal(thread, obj, 1);
+}
 
 #ifdef	__cplusplus
 };
diff -Nur orig/pnet/engine/process.c work.xxx/pnet/engine/process.c
--- orig/pnet/engine/process.c	2003-11-03 15:18:21.000000000 +1000
+++ work.xxx/pnet/engine/process.c	2004-05-04 18:40:50.000000000 +1000
@@ -61,9 +61,6 @@
 	process->firstThread = 0;
 	process->mainThread = 0;
 	process->finalizerThread = 0;
-#ifdef USE_HASHING_MONITORS
-	process->monitorHash = 0;
-#endif
 	process->stackSize = ((stackSize < IL_CONFIG_STACK_SIZE)
 							? IL_CONFIG_STACK_SIZE : stackSize);
 	process->frameStackSize = IL_CONFIG_FRAME_STACK_SIZE;
@@ -125,16 +122,6 @@
 		return 0;
 	}
 
-#ifdef USE_HASHING_MONITORS
-	/* Initialize the monitor system lock */
-	process->monitorSystemLock = ILMutexCreate();
-	if(!(process->monitorSystemLock))
-	{
-		ILExecProcessDestroy(process);
-		return 0;
-	}
-#endif
-
 	/* Initialize the finalization context */
 	process->finalizationContext = (ILFinalizationContext *)ILGCAlloc(sizeof(ILFinalizationContext));
 	if (!process->finalizationContext)
@@ -167,6 +154,12 @@
 	{
 		process->finalizerThread = process->mainThread;
 	}
+
+	if (!_ILMonitorProcessInit(process))
+	{
+		ILExecProcessDestroy(process);
+		return 0;
+	}
 	
 	/* Initialize the random seed pool lock */
 	process->randomLock = ILMutexCreate();
@@ -441,10 +434,7 @@
 		ILMemZero(process->randomPool, sizeof(process->randomPool));
 	}
 
-#ifdef USE_HASHING_MONITORS
-	/* Destroy the monitor system lock */
-	ILMutexDestroy(process->monitorSystemLock);
-#endif
+	_ILMonitorProcessDestroy(process);
 
 	if (process->lock)
 	{
diff -Nur orig/pnet/engine/thread.c work.xxx/pnet/engine/thread.c
--- orig/pnet/engine/thread.c	2003-08-19 15:56:59.000000000 +1000
+++ work.xxx/pnet/engine/thread.c	2004-05-04 18:40:50.000000000 +1000
@@ -177,7 +177,6 @@
 	thread->supportThread = 0;
 	thread->aborting = 0;
 	thread->clrThread = 0;	
-	thread->freeMonitor = 0;	
 	thread->pc = 0;
 	thread->isFinalizerThread = 0;
 	thread->frame = thread->stackBase;
@@ -206,7 +205,6 @@
 
 void _ILExecThreadDestroy(ILExecThread *thread)
 {
-	ILExecMonitor *monitor, *next;
 	ILExecProcess *process = thread->process;
 
 	/* Lock down the process */
@@ -223,17 +221,6 @@
 		process->finalizerThread = 0;
 	}
 
-	/* Delete the free monitors list */
-
-	monitor = thread->freeMonitor;
-
-	while (monitor)
-	{
-		next = monitor->next;
-		ILExecMonitorDestroy(monitor);
-		monitor = next;
-	}
-
 	/* Detach the thread from its process */
 	if(thread->nextThread)
 	{
diff -Nur orig/pnet/include/il_engine.h work.xxx/pnet/include/il_engine.h
--- orig/pnet/include/il_engine.h	2003-07-20 07:05:44.000000000 +1000
+++ work.xxx/pnet/include/il_engine.h	2004-05-04 18:40:50.000000000 +1000
@@ -29,11 +29,6 @@
 #endif
 
 /*
- *	Structure used by the EE for storing monitors.
- */
-typedef struct _tagILExecMonitor ILExecMonitor;
-
-/*
  * Execution control context for a process.
  */
 typedef struct _tagILExecProcess ILExecProcess;
diff -Nur orig/pnet/include/il_gc.h work.xxx/pnet/include/il_gc.h
--- orig/pnet/include/il_gc.h	2003-06-26 13:39:25.000000000 +1000
+++ work.xxx/pnet/include/il_gc.h	2004-05-04 18:40:50.000000000 +1000
@@ -47,12 +47,20 @@
 
 /*
  * Allocate a block of memory from the garbage collector
- * that will never contain pointers.  Use this for allocating
- * arrays of atomic numeric types.  The block is zero'ed.
+ * that will never contain pointers.  The block is zero'ed.
  */
 void *ILGCAllocAtomic(unsigned long size);
 
 /*
+ * Allocate a block of memory from the garbage collector
+ * that starts with a header and is followed by data.
+ * The data will never contain pointers.  Use this for
+ * allocating arrays of atomic numeric types.  The block
+ * is zero'ed.
+ */
+void *ILGCAllocAtomicHeader(unsigned long size, unsigned long headerSize);
+
+/*
  * Allocate a block of memory that is persistent.  It will
  * not be collected until explicited free'd, but it will
  * still be scanned for object pointers.
diff -Nur orig/pnet/include/il_thread.h work.xxx/pnet/include/il_thread.h
--- orig/pnet/include/il_thread.h	2004-05-04 17:37:08.000000000 +1000
+++ work.xxx/pnet/include/il_thread.h	2004-05-04 18:40:50.000000000 +1000
@@ -237,6 +237,13 @@
 void ILThreadMemoryBarrier(void);
 
 /*
+ * Check if a pointer holds a given value, and if so set it.  The
+ * old value held in the pointer is returned.  This is an atomic
+ * operation - it can not be interrupted by other threads.
+ */
+void* ILThreadCompareAndSwapPtr(void** ptr, void* newValue, void* compareValue);
+
+/*
  * Get the number of foreground and background threads
  * that currently exist in the system.
  */
@@ -400,33 +407,15 @@
 int ILWaitMonitorWait(ILWaitHandle *handle, ILUInt32 timeout);
 
 /*
- * Pulse a single waiting thread on a monitor.
- */
-int ILWaitMonitorPulse(ILWaitHandle *handle);
-
-/*
- * Pulse all waiting threads on a monitor.
+ * Pulse a monitor.  If the parameter all is false, at most one
+ * thread will be relased.  If all is true, every waiting thread
+ * waiting on the monitor will be woken up.
  */
-int ILWaitMonitorPulseAll(ILWaitHandle *handle);
-
-/*
- *	Checks if the monitor has no owner and no waiters.
- */
-int ILWaitMonitorCanClose(ILWaitHandle *handle);
+int ILWaitMonitorPulse(ILWaitHandle *handle, ILBool all);
 
 #define IL_WAIT_LEAVE_STILL_OWNS		(2)
 
 /*
- *	Similar to ILWaitMonitorLeave except that waiting moniters aren't signalled.
- */
-int ILWaitMonitorSpeculativeLeave(ILWaitHandle *handle);
-
-/*
- *	Signals waiting monitors when call after ILWaitMonitorSpeculativeLeave.
- */
-int ILWaitMonitorCompleteLeave(ILWaitHandle *handle);
-
-/*
  * Fast way to "enter" or "claim" a monitor if you know for sure that no other thread
  * can contest the claim.  For example, A newly created monitor that is only known by
  * one thread can be safely fast-claimed.
diff -Nur orig/pnet/support/def_gc.c work.xxx/pnet/support/def_gc.c
--- orig/pnet/support/def_gc.c	2003-06-26 13:39:25.000000000 +1000
+++ work.xxx/pnet/support/def_gc.c	2004-05-04 18:40:50.000000000 +1000
@@ -149,6 +149,12 @@
 	return ILGCAlloc(size);
 }
 
+void *ILGCAllocAtomicHeader(unsigned long size, unsigned long headerSize)
+{
+	/* There's no difference between normal and atomic memory */
+	return ILGCAlloc(size);
+}
+
 void *ILGCAllocPersistent(unsigned long size)
 {
 	/* There's no difference between normal and persistent memory */
diff -Nur orig/pnet/support/hb_gc.c work.xxx/pnet/support/hb_gc.c
--- orig/pnet/support/hb_gc.c	2003-07-16 11:30:45.000000000 +1000
+++ work.xxx/pnet/support/hb_gc.c	2004-05-04 18:40:50.000000000 +1000
@@ -28,6 +28,7 @@
 #ifdef HAVE_LIBGC
 
 #include "../libgc/include/gc.h"
+#include "../libgc/include/gc_typed.h"
 
 #ifdef	__cplusplus
 extern	"C" {
@@ -77,6 +78,12 @@
 static ILWaitHandle *_FinalizerResponse = 0;
 
 /*
+ *	Descriptors for typed allocations.  Indexed by the number of
+ *	words in the header.
+ */
+static GC_descr alloc_types[16];
+
+/*
  *	Tracing macros for the GC.
  */
 #ifdef GC_TRACE_ENABLE
@@ -326,6 +333,58 @@
 	return block;
 }
 
+void *ILGCAllocAtomicHeader(unsigned long size, unsigned long headerSize)
+{
+	GC_word bitmap[GC_BITMAP_SIZE(sizeof(alloc_types) / sizeof(alloc_types[0]) * sizeof(GC_word))];
+	GC_descr descriptor;
+	int i;
+	size_t wordsInHeader;
+
+	/*
+	 * Handle the silly case first.
+	 */
+	if (headerSize == 0)
+	{
+		return ILGCAllocAtomic(size);
+	}
+	/*
+	 * The Hans-Boehm way of doing this is to create a type descriptor,
+	 * which describes the words in the allocated block that might have
+	 * pointers in them.  Type descriptors are a limited resource, and
+	 * you can't free them, so they must be cached.
+	 *
+	 * See if there is a type descriptor for this particular header size.
+	 */
+	wordsInHeader =
+		(size_t)((headerSize + sizeof(GC_word)-1) / sizeof(GC_word));
+	if(wordsInHeader > sizeof(alloc_types) / sizeof(alloc_types[0]))
+	{
+		return 0;
+	}
+    descriptor = alloc_types[wordsInHeader-1];
+	/*
+	 * If there isn't a type descriptor create one.
+	 */
+	if(descriptor == 0)
+	{
+		ILMemZero(bitmap, sizeof(bitmap));
+		for (i = 0; i < wordsInHeader; i += 1)
+		{
+			GC_set_bit(bitmap, i);
+		}
+		descriptor = GC_make_descriptor(bitmap, wordsInHeader);
+		if (descriptor == 0)
+		{
+			return 0;
+		}
+		alloc_types[wordsInHeader-1] = descriptor;
+	}
+    /*
+	 * Allocate the block, which is guarenteed to be zero-ed.
+	 */
+	return GC_MALLOC_EXPLICITLY_TYPED((size_t)size, descriptor);
+}
+
 void *ILGCAllocPersistent(unsigned long size)
 {
 	/* The Hans-Boehm routines guarantee to zero the block */
diff -Nur orig/pnet/support/thread.c work.xxx/pnet/support/thread.c
--- orig/pnet/support/thread.c	2004-05-04 17:37:12.000000000 +1000
+++ work.xxx/pnet/support/thread.c	2004-05-04 18:40:50.000000000 +1000
@@ -776,6 +776,22 @@
 	_ILMutexUnlock(&atomicLock);
 }
 
+void* ILThreadCompareAndSwapPtr(void** ptr, void* newValue, void* currentValue)
+{
+	/* For now, we just get a global lock.  On architures that support
+	 * bus locks or similar (eg i386), this can be refined to a single
+	 * instruction.  Doing that would speed up monitors.
+	 */
+	void* orig;
+	ILThreadAtomicStart();
+	if((orig = *ptr) == currentValue)
+	{
+		*ptr = newValue;
+	}
+	ILThreadAtomicEnd();
+	return orig;
+}
+
 void ILThreadGetCounts(unsigned long *numForeground,
 					   unsigned long *numBackground)
 {
diff -Nur orig/pnet/support/wait_mutex.c work.xxx/pnet/support/wait_mutex.c
--- orig/pnet/support/wait_mutex.c	2004-05-04 08:13:11.000000000 +1000
+++ work.xxx/pnet/support/wait_mutex.c	2004-05-04 18:40:50.000000000 +1000
@@ -128,39 +128,6 @@
 	return IL_WAITCLOSE_FREE;
 }
 
-int ILWaitMonitorFastClaim(ILWaitHandle *handle)
-{
-	ILThread *thread = ILThreadSelf();
-	ILWaitMutex *mutex = (ILWaitMutex *)handle;
-
-	mutex->owner = &thread->wakeup;
-	mutex->count = 1;
-
-	if ((thread->state & (IL_TS_ABORTED | IL_TS_ABORT_REQUESTED)) != 0)
-	{
-		/* Do a slower safer double check */
-		
-		_ILMutexLock(&(thread->lock));
-
-		if ((thread->state & (IL_TS_ABORTED | IL_TS_ABORT_REQUESTED)) != 0)
-		{
-			_ILMutexUnlock(&(thread->lock));
-			
-			return IL_WAIT_ABORTED;
-		}
-		else
-		{
-			_ILMutexUnlock(&(thread->lock));
-
-			return 0;
-		}
-	}
-	else
-	{
-		return 0;
-	}
-}
-
 /*
  * Register a wakeup object with a wait mutex.
  */
@@ -382,7 +349,7 @@
 	return &(mutex->parent.parent);
 }
 
-int PrivateILWaitMutexRelease(ILWaitHandle *handle, int mode)
+int ILWaitMutexRelease(ILWaitHandle *handle)
 {
 	ILWaitMutex *mutex = (ILWaitMutex *)handle;
 	int result;
@@ -401,43 +368,17 @@
 		/* This thread doesn't currently own the mutex */
 		result = 0;
 	}
-	else if (mode == 2)
-	{
-		/* Complete a release (after a call with mode = 1) */
-		
-		if (mutex->count == 0)
-		{
-			mutex->owner = _ILWakeupQueueWake(&(mutex->queue));
-			if(mutex->owner != 0)
-			{
-				mutex->count = 1;
-			}
-		}
-
-		result = 1;
-	}
 	else if(--(mutex->count) == 0)
 	{
 		/* The count has returned to zero, so find something
 		   else to give the ownership of the mutex to */
 
-		if (mode == 0)
-		{
-			mutex->owner = _ILWakeupQueueWake(&(mutex->queue));
-			if(mutex->owner != 0)
-			{
-				mutex->count = 1;
-			}
-			result = 1;
-		}
-		else if (mode == 1)
-		{
-			result = 1;
-		}
-		else
+		mutex->owner = _ILWakeupQueueWake(&(mutex->queue));
+		if(mutex->owner != 0)
 		{
-			result = 0;
+			mutex->count = 1;
 		}
+		result = 1;
 	}
 	else
 	{
@@ -450,11 +391,6 @@
 	return result;
 }
 
-int ILWaitMutexRelease(ILWaitHandle *handle)
-{
-	return PrivateILWaitMutexRelease(handle, 0);
-}
-
 /*
  * Close a monitor.
  */
@@ -611,38 +547,7 @@
 	return LeaveWait(ILThreadSelf(), result);
 }
 
-int ILWaitMonitorPulse(ILWaitHandle *handle)
-{
-	ILMonitor *monitor = (ILMonitor *)handle;
-	_ILWakeup *wakeup = &((ILThreadSelf())->wakeup);
-	int result;
-
-	/* Lock down the monitor */
-	_ILMutexLock(&(monitor->parent.parent.lock));
-
-	/* Determine what to do based on the monitor's state */
-	if(monitor->parent.parent.kind != IL_WAIT_MONITOR)
-	{
-		/* This isn't actually a monitor */
-		result = 0;
-	}
-	else if(monitor->parent.owner != wakeup)
-	{
-		/* This thread doesn't currently own the monitor */
-		result = 0;
-	}
-	else
-	{
-		/* Wake up something on the signal queue */
-		_ILWakeupQueueWake(&(monitor->signalQueue));
-		result = 1;
-	}
-	/* Unlock the monitor and return */
-	_ILMutexUnlock(&(monitor->parent.parent.lock));
-	return result;
-}
-
-int ILWaitMonitorPulseAll(ILWaitHandle *handle)
+int ILWaitMonitorPulse(ILWaitHandle *handle, ILBool all)
 {
 	ILMonitor *monitor = (ILMonitor *)handle;
 	_ILWakeup *wakeup = &((ILThreadSelf())->wakeup);
@@ -664,47 +569,23 @@
 	}
 	else
 	{
-		/* Wake up everything on the signal queue */
-		_ILWakeupQueueWakeAll(&(monitor->signalQueue));
+	  	if(!all)
+		{
+			/* Wake up something on the signal queue */
+			_ILWakeupQueueWake(&(monitor->signalQueue));
+		}
+		else
+		{
+			/* Wake up everything on the signal queue */
+			_ILWakeupQueueWakeAll(&(monitor->signalQueue));
+		}
 		result = 1;
 	}
-
 	/* Unlock the monitor and return */
 	_ILMutexUnlock(&(monitor->parent.parent.lock));
 	return result;
 }
 
-int ILWaitMonitorCanClose(ILWaitHandle *handle)
-{
-	ILMonitor *monitor = (ILMonitor *)handle;
-
-	_ILMutexLock(&(monitor->parent.parent.lock));
-
-	if(monitor->parent.count == 0 && monitor->waiters == 0
-		&& _ILWakeupQueueIsEmpty(&(monitor->parent.queue)))
-	{
-		_ILMutexUnlock(&(monitor->parent.parent.lock));
-
-		return 1;
-	}
-	else
-	{
-		_ILMutexUnlock(&(monitor->parent.parent.lock));
-
-		return 0;	
-	}
-}
-
-int ILWaitMonitorSpeculativeLeave(ILWaitHandle *handle)
-{
-	return PrivateILWaitMutexRelease(handle, 1);
-}
-
-int ILWaitMonitorCompleteLeave(ILWaitHandle *handle)
-{
-	return PrivateILWaitMutexRelease(handle, 2);
-}
-
 #ifdef	__cplusplus
 };
 #endif
