Mutex implementation
Posted: Fri Sep 14, 2012 1:16 pm
Hi,
I've been referring to the wiki since some time though I'm new to the forums here. I am working on a preemptive multitasking system for ARM, It's an educational project for me. Below is the implementation I have written for mutex objects, I'd like to know if there are possible better implementations or maybe a bug/lockups. Though i don't intend to use it on a multicore system, it wouldn't hurt to support them for future extensibility. Thank you for your time and help
I've been referring to the wiki since some time though I'm new to the forums here. I am working on a preemptive multitasking system for ARM, It's an educational project for me. Below is the implementation I have written for mutex objects, I'd like to know if there are possible better implementations or maybe a bug/lockups. Though i don't intend to use it on a multicore system, it wouldn't hurt to support them for future extensibility. Thank you for your time and help
Code: Select all
/*******************************************************************************
* @File mutex.c
* @Date 22nd September 2012
* @Brief SMP implementation of mutex
* Structure size should be (4 + wait_queue_t) bytes
*
* For more info, Read /notes/thread-safety
*
* @Authors
* Shantanu Gupta <shans95g AT gmail.com>
******************************************************************************/
#include <os.h>
#include <cpu.h>
#include <mutex.h>
#include <thread.h>
#include <spinlock.h>
OS_INLINE OS_ERR mutex_acquire_try(mutex_t *mutex)
{
if(unlikely(cpu_atomic_cmpxchg((void *)&mutex->owner, current_thread, OS_NULL) != OS_EOKAY))
return OS_EBUSY;
return OS_EOKAY;
}
OS_ERR mutex_acquire_timeout(mutex_t *mutex, time_t timeout)
{
if(unlikely(mutex_acquire_try(mutex) != OS_EOKAY))
{
spinlock_acquire(&mutex->lock);
while(unlikely(mutex_acquire_try(mutex) != OS_EOKAY))
{
thread_boost(mutex->owner);
spinlock_release(&mutex->lock);
if(thread_block(&mutex->queue, timeout) != OS_EOKAY)
return OS_EBUSY;
spinlock_acquire(&mutex->lock);
}
spinlock_release(&mutex->lock);
}
return OS_EOKAY;
}
void mutex_acquire(mutex_t *mutex)
{
if(unlikely(mutex_acquire_try(mutex) != OS_EOKAY))
{
spinlock_acquire(&mutex->lock);
while(unlikely(mutex_acquire_try(mutex) != OS_EOKAY))
{
thread_boost(mutex->owner);
spinlock_release(&mutex->lock);
thread_block(&mutex->queue, timeout);
spinlock_acquire(&mutex->lock);
}
spinlock_release(&mutex->lock);
}
}
OS_INLINE void mutex_release(mutex_t *mutex)
{
#ifdef DEBUG
/* In good code, release should only be called if acquire was successful */
if(unlikely((mutex->owner) != current_thread))
{
LOGF("%s: TCB %p OBJ %p\n", __func__, current_thread, (void *) mutex);
} else
#endif
{
spinlock_acquire(mutex->lock);
mutex->owner = OS_NULL;
spinlock_release(mutex->lock);
thread_queue_wake_one_sync(&mutex->queue);
}
}
OS_INLINE void mutex_init(mutex_t *mutex)
{
mutex->owner = OS_NULL;
spinlock_init(mutex->lock);
thread_queue_init(&mutex->queue);
}