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);
}