bug in limit checks and threads

Stephen Weeks sweeks@intertrust.com
Wed, 4 Oct 2000 11:20:36 -0700 (PDT)


> There is currently a bug in the way thread switching is handled.  The problem is
> caused by the fact that limit check points are the same as context switch
> points.  The bug is that a thread checks that there is enough space available
> before switching to another thread and not when it resumes.  Hence there is no
> guarantee that there is enough space when the thread resumes.  There are three
> possible fixes I see to this problem.
> 
> 1. Save the bytesRequested as part of the gc state and have the gc check it
>    upon resumption.
> 2. Have the LimitCheck code include a loop that checks again, upon return from
>    the GC.
> 3. Have some global max over all (fixed-size) limit checks that the GC
>    guarantees is available upon thread resumption.  Disallow thread switches
>    at variable-sized limit check points.
> 
> Any opinions on which way is the right way to go?  Other solutions?

I went ahead with a slight modification of Henry's suggestion, which was

> I would guess that the time overhead of changing
> 	if (less than ??? space)
> 		do_GC(...);
> to
> 	while (less than ??? space)
> 		do_GC(...);
> should be quite minimal, so I would probably vote for that.

To avoid any runtime cost, I left the if test in limit checks alone, and put a
loop inside the gc case.  Here is the new LimitCheck macro.

#define LimitCheck(frameSize, ret, b, other)					\
	do {									\
		declareFirst;							\
										\
		if (INSTRUMENT)							\
			MLton_numLimitChecks++;					\
		if (GC_EVERY_CHECK						\
		or (GC_FIRST_CHECK and gc_first)				\
		or frontier + (b) > gcState.limit				\
		or (other)) {							\
			do {							\
			uint bytes = b;						\
										\
			InvokeRuntime(GC_gc(&gcState, bytes,			\
						GC_EVERY_CHECK or		\
						(GC_FIRST_CHECK and gc_first),	\
						__FILE__, __LINE__),		\
					frameSize, ret);			\
			} while (frontier + (b) > gcState.limit);		\
			clearFirst;						\
		}								\
		assert(gcState.stackBottom <= stackTop + WORD_SIZE);		\
	} while (0)