Page 1 of 1

Basic questions about theLOCK, it doesn't work as I thought.

Posted: Wed Sep 09, 2009 2:05 am
by nicesj
Hello,.

Currently I'm implementing some synchronization methods such as spinlock, semaphore, mutex, ...

But those are not working correctly,. so I paste some codes from my kernel to here.
Would you let me know what I've missed?
Thank you..

Code: Select all

void spinlock_lock(spin_lock_t *handle)
{
//      while (handle->lock) DbgPrint("a %p\n", kthread_get_current());
//      handle->lock = 1;
//      return;
//      cursor_set_pos(0, 0);
//      DbgPrint("===== [Task %p] =====\n", kthread_get_current());

        asm __volatile__ (
//              "cli\n"
                "clc\n"
                "1:\n"
                "lock; btsl $0, %0\n"
//              "sti\n"
//              "nop; nop; nop; nop\n"
//              "nop; nop; nop; nop\n"
//              "cli\n"
                "jc 1b\n"
//              "sti\n"
                :
                : "m"(handle->lock)
                : "memory"
        );

//      PANIC("Locked %d\n", handle->lock);
//      if (handle->lock > 1) PANIC("Error\n");
}
When I enable the "nop" instruction, only one thread works, (there are 3 threads are exists)
but if I disable "nop" instruction, no threads are woking,. and the kernel starting to busy-waiting. :(

Re: Basic questions about theLOCK, it doesn't work as I thought.

Posted: Wed Sep 09, 2009 5:41 am
by JamesM
Hi,

The LOCK prefix just locks the bus; you say three "threads" are running, are those on different cores? If they're on the same core just timesliced, the LOCK prefix will have absolutely no effect.

For mutexes and semaphores, the instruction you want to look at is "lock cmpxchg". Or you could do what I do and use the GCC builtins.

Re: Basic questions about theLOCK, it doesn't work as I thought.

Posted: Sat Sep 12, 2009 8:30 am
by nicesj
only you have interested on me. Thank you James,M

I found the timing problem,. timer interrupt does not occurs between release spin-lock, and re-acquire spin-lock.
even if A thread releases the spin-lock, timer interrupt does not occurs before acquiring spinlock again.
so the only one thread can get the lock, there is no time to get the lock by other thread.

To solve this problem, I have added a trap, which is invoke the scheduler forcely.

here is the code of my spinlock implementation.
(I have changed the asm code from using btsl/btrl to using xchg, there is no differences to implement the spinlock, but many people uses xchg instead of btsl/btrl, so I decide to follow them,. there is no other intension or problem..:)


// Unlock

Code: Select all

        asm __volatile__ (
                "movl $0, %%eax;\n"
                "xchgl %0, %%eax;\n"
                "int $0x30\n"   // yield
                : "=m"(handle->lock)
                : "m"(handle->lock)
                : "memory", "%eax"
        );
// Lock

Code: Select all

 
       asm __volatile__ (
                "movl $1, %%eax\n"
                "1:\n"
                "xchgl %0, %%eax;\n"
                "testl %%eax, %%eax;\n"
                "jnz 1b\n"
                : "=m"(handle->lock)
                : "m"(handle->lock)
                : "memory", "%eax"
        );      

If I have missed something, or anybody knows more better way to solve this timing problem, would you let me know it?
Thank you.

and I will use builtin functions to handes atomic variables in the near future. Thanks James,M.

Re: Basic questions about theLOCK, it doesn't work as I thought.

Posted: Sun Sep 13, 2009 10:18 am
by JamesM
nicesj wrote:only you have interested on me. Thank you James,M

I found the timing problem,. timer interrupt does not occurs between release spin-lock, and re-acquire spin-lock.
even if A thread releases the spin-lock, timer interrupt does not occurs before acquiring spinlock again.
so the only one thread can get the lock, there is no time to get the lock by other thread.

To solve this problem, I have added a trap, which is invoke the scheduler forcely.

here is the code of my spinlock implementation.
(I have changed the asm code from using btsl/btrl to using xchg, there is no differences to implement the spinlock, but many people uses xchg instead of btsl/btrl, so I decide to follow them,. there is no other intension or problem..:)


// Unlock

Code: Select all

        asm __volatile__ (
                "movl $0, %%eax;\n"
                "xchgl %0, %%eax;\n"
                "int $0x30\n"   // yield
                : "=m"(handle->lock)
                : "m"(handle->lock)
                : "memory", "%eax"
        );
// Lock

Code: Select all

 
       asm __volatile__ (
                "movl $1, %%eax\n"
                "1:\n"
                "xchgl %0, %%eax;\n"
                "testl %%eax, %%eax;\n"
                "jnz 1b\n"
                : "=m"(handle->lock)
                : "m"(handle->lock)
                : "memory", "%eax"
        );      

If I have missed something, or anybody knows more better way to solve this timing problem, would you let me know it?
Thank you.

and I will use builtin functions to handes atomic variables in the near future. Thanks James,M.

Hi, you don't appear to be changing interrupts anywhere - have you actually "sti"'d? Are you sure interrupts are enabled?

The PIC queues up pending interrupts, and when you set the "IF" flag in EFLAGS, the PIC immediately dispatches an interrupt. So you see it is impossible for the lock to be released then locked again before a queued interrupt is serviced.

It sounds like you have a stray "cli" somewhere.