Subject: kern_sem.c
To: None <tech-kern@netbsd.org>
From: Simon J. Gerraty <sjg@quick.com.au>
List: tech-kern
Date: 02/27/2001 00:57:55
So, I've implemented semaphores in the kernel - for the purpose of
forcing the boot cpu (Hypersparc) to wait for other cpu's to flush
cache entries before unmapping the page.  This seems to do the trick,
an MP kernel on a dual hypersparc SS20 can get to start_init() now
(see my post to tech-smp)

There's still a lot of work to be done on the sparc, but I think the
semaphores achieved the desired goal.  So I'm wondering if its worth
committing kern/kern_sem.c and sys/ksem.h now - even though virtually
nothing uses them (other than my local arch/sparc/sparc/cache.c), so
that those with more kernel clue than I, can take a look and probably
fix the obvious bugs.

Note semaphores are not the answer to many issues that the MP kernels
face, but in the case of hypersparc cpu's semaphores or a moral equiv
are probably necessary. 

The implementation is currently very simple and MI.  If semaphores get
used enough it might be worth doing MD implementations but time will
tell. 

typedef struct sema_s {
	struct simplelock sem_interlock;
	const char *sem_wmesg;
	int	sem_flags;
	int	sem_sleepers;
	int	sem_count;
} sema_t;

#define SEMAF_VALID (1<<0)		/* initialized */
#define SEMAF_DEBUG (1<<1)

void	sema_init(sema_t *sp, int cnt, const char *wmesg, int flags);
void	sema_setflags(sema_t *sp, int flags);
void	sema_spinwait(sema_t *sp);	/* spin version of P() */
void	sema_wait(sema_t *sp);		/* sleep version of P() */
int	sema_signal(sema_t *sp);	/* V() */

In the case of the sparc smp_cache_flush() et al, the semaphore is
initialized on entry to the smp*flush routine, and each single cpu
version does a sema_signal() after flushing.  The smp*flush routine
then does a sema_wait() for each cpu, and when all done, marks the
semaphore as invalid.   This is the main use of sema_setflags().


sema_spinwait() does just that.

sema_wait() increments sleepers before sleeping, and sema_signal()
only calls wakeup_one() if sleepers > 0.  sema_signal() returns the
value of sem_count, so that one can know whether there might be anyone
sleeping on it.  When sema_setflags is being asked to invalidate the
semaphore, it calls sema_signal() to ensure no one is sleeping on it.

Thoughts?
--sjg