thread runtime system bug

Stephen Weeks MLton@sourcelight.com
Thu, 5 Jul 2001 17:03:16 -0700


I have tracked down a thread bug to the following.

Here is the relevant code:
* handler is the C signal handler
* Thread_atomicBegin is called to start a critical section
* gcState is declared with 
	extern struct GC_state gcState;

--------------------------------------------------

static void handler(Int signum) {
	GC_handler(&gcState, signum);
}

void GC_handler(GC_state s, int signum) {
	if (DEBUG)
		fprintf(stderr, "GC_handler\n");
	if (0 == s->canHandle) {
		if (DEBUG)
			fprintf(stderr, "setting limit = base\n");
		s->limit = s->base;
	}
	sigaddset(&s->signalsPending, signum);
	s->signalIsPending = TRUE;
}


void Thread_atomicBegin() {
	if (DEBUG)
		fprintf(stderr, "atomicBegin %d -> %d\n", 
				gcState.canHandle, gcState.canHandle + 1);
	assert(gcState.canHandle >= 0);
 	gcState.canHandle++;
	if (FALSE and DEBUG)
		fprintf(stderr, "atomicBegin canHandle++ done\n");
	if (gcState.signalIsPending) {
		if (DEBUG)
			fprintf(stderr, "atomicBegin signal pending\n");
		setLimit(&gcState);
	} else {
		if (DEBUG)
			fprintf(stderr, "atomicBegin no signal pending\n");
	}
	if (DEBUG)
		fprintf(stderr, "atomicBegin done\n");
}

--------------------------------------------------

When running, I see the following on stderr

atomicBegin 0 -> 1
GC_handler
setting limit = base
atomicBegin no signal pending
atomicBegin done

What this tells me is that the following sequence of events happens.
1. Thread_atomicBegin starts running
2. A signal arrives before the gcState.canHandle++ statement
3. The handler runs, sets limit to base and sets signalIsPending.
4. Thread_atomicBegin continues, but does not see that signalIsPending.

My question: is this because gcState is not declared volatile?  Should it be?
I certainly intended when I wrote the code for Thread_atomicBegin for it to work
correctly if it is interrupted by the C signal handler.