lkml.org 
[lkml]   [1999]   [Nov]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [Patch] shm bug introduced with pagecache in 2.3.11
"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
/* 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();
}


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);
}
\
 
 \ /
  Last update: 2005-03-22 13:55    [W:0.073 / U:0.856 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site