[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-kernel
Subject:    Re: [Patch] shm bug introduced with pagecache in 2.3.11
From:       Manfred Spraul <manfreds () colorfullife ! com>
Date:       1999-11-20 20:31:09
[Download RAW message or body]

"Benjamin C.R. LaHaise" wrote:
> 
> On Fri, 19 Nov 1999, Linus Torvalds wrote:
> 
> > Is anybody willing to take a stab at creating a read-write semaphore?
> 
> Sure.  Does the following sound?
> 
>         void down_read(struct rw_semaphore *sem);
>         void down_write(struct rw_semaphore *sem);
>         void up_read(struct rw_semaphore *sem);
>         void up_write(struct rw_semaphore *sem);
> 
> Looking at existing semaphores and rwlocks, it looks like a quick and
> painless beast to create.
> 
>                 -ben
I give it up:
I've attached 2 more ideas, but one of them is a bit slow, and the other
one requires cmpxchg (ie only 486 and above).

--
	Manfred
["do2.c" (text/plain)]

/* need_wakeup is required because I must differenciate between
 * a) release the lock
 * b) release the lock, and wake-up another thread.
 *
 * a normal semaphore is an integer, and if it is below
 * zero, then a wake-up is required.
 * the write-lock is just one bit, therefore
 * I need the explicit "rwm->need_wakeup" variable.
 */

struct rw_mutex
{
	volatile unsigned int lock;
	int need_wakeup;
	wait_queue_head wait;
};

void rw_mutex_init(struct rw_mutex* rwm)
{
	rwm->count=0;
	init_wait_queue_head(&rwm->wait);
}

/* i486: 4 asm instructions inline, 1 LOCK */
void acquire_exclusive(struct rw_mutex* rwm)
{
	eax=0
	ebx=0x8000 0000
	cmpxchg ebx,rwm->lock
	jnz ok
	__acquire_failed();
ok:
}

/* 2 asm instruction inline, 1 LOCK */
void acquire_shared(struct rw_mutex* rwm)
{
	inc rwm->lock
	jns ok 
	dec rwm->lock

	__acquire_failed()
ok:
}

void __acquire_failed()
{
	DECLARE_WAITQUEUE(wait,current)
	add_wait_queue(wait,&rwm->wait);
	for(;;) {
		rwm->need_wakeup = 1;
		set_current_state();
		/* rmb() */
		if(lock_is_free)
			break;
		schedule();
	}
	remove_wait_queue();

}
/* 3 asm instructions, 1 LOCK.*/
void release_exclusive(struct rw_mutex* rwm)
{
	lock orl 0x7ffffffff,rwm->lock /* LOCK required for memory ordering */	
	if(rwm->need_wakeup)
		__wake_up();
}

/* 3 asm instructions, 1 LOCK.*/
void release_shared(struct rw_mutex* rwm)
{
	lock dec rwm->lock /* LOCK required for memory ordering */
	if(rwm->need_wakeup)
		__wake_up();
}


["do.c" (text/plain)]

struct rw_mutex
{
	struct semaphore s1;
	struct semaphore s1;
	int count;
};

void rw_mutex_init(struct rw_mutex* rwm)
{
	sema_init(&rwm->s1,1);
	sema_init(&rwm->s2,1);
	count=-1;
}

/* i386: 4 asm instructions inline, 2 LOCK */
void acquire_exclusive(struct rw_mutex* rwm)
{
	down(&rwm->s1); /* this down is only required for fairness */
	down(&rwm->s2);
}

/* 8 asm instruction inline, 3 LOCK */
void acquire_shared(struct rw_mutex* rwm)
{
	down(&rwm->s1);
	rwm->count++;
	if(rwm->count==0) /* zero-flag*/
		down(&rwm->s2);
	up(&rwm->s1);
}

/* 4 asm instructions, 2 LOCK.*/
void release_exclusive(struct rw_mutex* rwm)
{
	up(&rwm->s2);
	up(&rwm->s1); /* this up is only required for fairness */

	/* it would possible to merge both up-calls into one
	 * 'lock; orl', but then I need 'rwm->need_wakeup',
	 * and I must replace the 'incl' in down(&sem)
	 * with a (slower) 'bts'. */
}

/* 4 asm instructions, 2 LOCK.*/
void release_shared(struct rw_mutex* rwm)
{
	down(&rwm->s1); /* not required with inline asm */
	rwm->count--;
	if(rwm->count < 0) /* sign-flag */
		up(&rwm->s2);
	up(&rwm->s2);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic