0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-06-14 11:22:09 +00:00
Files
2022-01-04 12:22:53 +02:00

1620 lines
43 KiB
C

/*HEADER*********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
***************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: mutex.c$
* $Version : 3.8.0.1$
* $Date : Feb-20-2012$
*
* Comments:
*
* This file contains functions of the Mutex component.
*
*END************************************************************************/
#include "mqx_inc.h"
#if MQX_USE_MUTEXES
#include "mutex.h"
#include "mutex_prv.h"
#if MQX_LITE_VERSION_NUMBER
MUTEX_COMPONENT_STRUCT mutex_struct;
#endif /* MQX_LITE_VERSION_NUMBER */
/*!
* \brief Initializes the mutex attributes structure to default values.
*
* This function initializes the mutex attributes structure to default values and
* validates the structure. It must be called before a task can modify the values
* of the mutex attributes structure. This function does not affect any mutexes
* already initialized with this structure.
*
* <table>
* <tr>
* <td><b> Mutex attribute </b></td>
* <td><b> Field in MUTEX_ATTR_STRUCT </b></td>
* <td><b> Default value </b></td>
* </tr>
* <tr>
* <td> Scheduling protocol </td>
* <td> POLICY </td>
* <td> MUTEX_NO_PRIO_INHERIT </td>
* </tr>
* <tr>
* <td> Valid </td>
* <td> VALID </td>
* <td> TRUE </td>
* </tr>
* <tr>
* <td> Priority </td>
* <td> PRIORITY </td>
* <td> 0 </td>
* </tr>
* <tr>
* <td> Spin limit </td>
* <td> COUNT </td>
* <td> 0 </td>
* </tr>
* <tr>
* <td> Waiting protocol </td>
* <td> WAITING POLICY </td>
* <td> MUTEX_QUEUEING </td>
* </tr>
* </table>
*
* \param[in] attr_ptr Pointer to the mutex attributes structure to initialize.
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL.)
*
* \see _mutex_init
* \see _mutatr_destroy
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_init
(
register MUTEX_ATTR_STRUCT_PTR attr_ptr
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE2(KLOG_mutatr_init, attr_ptr);
#if MQX_CHECK_ERRORS
if (attr_ptr == NULL)
{
_KLOGX2(KLOG_mutatr_init, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
attr_ptr->SCHED_PROTOCOL = MUTEX_NO_PRIO_INHERIT;
attr_ptr->PRIORITY_CEILING = 0;
attr_ptr->VALID = MUTEX_VALID;
attr_ptr->COUNT = 0;
attr_ptr->WAIT_PROTOCOL = MUTEX_QUEUEING;
_KLOGX2(KLOG_mutatr_init, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Installs the mutex component into the kernel.
*
* MQX calls this function if the mutex component is not created when a task calls
* _mutex_init().
*
* \return MQX_OK
* \return MQX_OUT_OF_MEMORY
*
* \see _mutex_init
* \see _mutatr_init
*/
_mqx_uint _mutex_create_component(void)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
register MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
_GET_KERNEL_DATA(kernel_data);
_KLOGE1(KLOG_mutex_create_component);
if (kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] != NULL)
{
_KLOGX2(KLOG_mutex_create_component, MQX_OK);
return (MQX_OK);
} /* Endif */
#if MQX_LITE_VERSION_NUMBER
mutex_component_ptr = &mutex_struct;
#else
mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) _mem_alloc_system_zero(
(_mem_size) sizeof(MUTEX_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (mutex_component_ptr == NULL)
{
_KLOGX2(KLOG_mutex_create_component, MQX_OUT_OF_MEMORY);
return (MQX_OUT_OF_MEMORY);
} /* Endif */
#endif
_mem_set_type(mutex_component_ptr, MEM_TYPE_MUTEX_COMPONENT);
#endif /* MQX_LITE_VERSION_NUMBER */
_QUEUE_INIT(&mutex_component_ptr->MUTEXES, 0);
mutex_component_ptr->VALID = MUTEX_VALID;
_int_disable();
#if MQX_CHECK_ERRORS
if (kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] != NULL)
{
_int_enable();
#if !MQX_LITE_VERSION_NUMBER
_mem_free(mutex_component_ptr);
#endif /* MQX_LITE_VERSION_NUMBER */
_KLOGX2(KLOG_mutex_create_component, MQX_OK);
return (MQX_OK);
} /* Endif */
#endif
kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] = mutex_component_ptr;
#if MQX_COMPONENT_DESTRUCTION
kernel_data->COMPONENT_CLEANUP[KERNEL_MUTEXES] = _mutex_cleanup;
#endif
_int_enable();
_KLOGX2(KLOG_mutex_create_component, MQX_OK);
return (MQX_OK);
} /* Endbody */
/*!
* \brief Deinitializes the mutex attributes structure.
*
* To reuse the mutex attributes structure, a task must reinitialize the structure.
*
* \param[in] attr_ptr Pointer to the mutex attributes structure; initialized
* with _mutatr_init().
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
*
* \see _mutatr_init
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_destroy
(
MUTEX_ATTR_STRUCT_PTR attr_ptr
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE2(KLOG_mutatr_destroy, attr_ptr);
#if MQX_CHECK_ERRORS
if (attr_ptr == NULL)
{
_KLOGX2(KLOG_mutatr_destroy, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutatr_destroy, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
attr_ptr->VALID = 0;
_KLOGX2(KLOG_mutatr_destroy, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Deinitializes the mutex.
*
* To reuse the mutex after it is destroyed, a task must reinitialize it with _mutex_create().
*
* \param[in] mutex_ptr Pointer to the mutex to be deinitialized.
*
* \return MQX_EOK
* \return MQX_COMPONENT_DOES_NOT_EXIST
* \return MQX_INVALID_COMPONENT_BASE (Mutex component data is not valid.)
* \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (From _mutex_lock: function cannot
* be called from an ISR.)
* \return MQX_EINVAL (From _mutex_lock: mutex_ptr was destroyed or is NULL.)
* \return MQX_EDEADLK (From _mutex_lock: task already has the mutex locked.)
* \return MQX_EBUSY (From _mutex_lock: mutex is already locked.)
*
* \warning Puts in their ready queues all tasks that are waiting for the mutex;
* their call to _mutex_lock() returns MQX_EINVAL.
*
* \see _mutex_init
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_destroy
(
register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
TD_STRUCT_PTR td_ptr;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mutex_destroy, mutex_ptr);
#if MQX_CHECK_ERRORS
if (kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] == NULL)
{
_KLOGX2(KLOG_mutex_destroy, MQX_COMPONENT_DOES_NOT_EXIST);
return (MQX_COMPONENT_DOES_NOT_EXIST);
} /* Endif */
#endif
mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
#if MQX_CHECK_VALIDITY
if (mutex_component_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_destroy, MQX_INVALID_COMPONENT_BASE);
return (MQX_INVALID_COMPONENT_BASE);
} /* Endif */
#endif
td_ptr = kernel_data->ACTIVE_PTR;
if (mutex_ptr->OWNER_TD != td_ptr)
{
result = _mutex_lock(mutex_ptr); /* Get the mutex */
if (result != MQX_EOK)
{
_KLOGX2(KLOG_mutex_destroy, result);
return (result);
} /* Endif */
} /* Endif */
mutex_ptr->VALID = 0;
if (mutex_ptr->LINK.NEXT != NULL)
{
/* Remove mutex from the queue of mutexes in the kernel */
_int_disable();
_QUEUE_REMOVE(&mutex_component_ptr->MUTEXES, mutex_ptr);
_int_enable();
} /* Endif */
/* Get rid of all waiting tasks */
while (_QUEUE_GET_SIZE(&mutex_ptr->WAITING_TASKS))
{
_QUEUE_DEQUEUE(&mutex_ptr->WAITING_TASKS, td_ptr);
_task_set_error_td_internal(td_ptr, MQX_EINVAL);
_int_disable();
_TASK_READY(td_ptr,kernel_data);
_int_enable();
} /* Endwhile */
td_ptr = kernel_data->ACTIVE_PTR;
_int_disable();
if (mutex_ptr->BOOSTED)
{
_sched_unboost_priority_internal(td_ptr, mutex_ptr->BOOSTED);
} /* Endif */
_int_enable();
_CHECK_RUN_SCHEDULER(); /* Let higher priority task run */
_KLOGX2(KLOG_mutex_destroy, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Gets the waiting policy of the mutex attributes structure.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes
* structure.
* \param[out] waiting_protocol_ptr Pointer to the current waiting protocol.
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attribute structure.)
*
* \see _mutatr_set_wait_protocol
* \see _mutatr_init
* \see _mutatr_get_spin_limit
* \see _mutatr_set_spin_limit
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_get_wait_protocol
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint_ptr waiting_protocol_ptr
)
{ /* Body */
#if MQX_CHECK_ERRORS
if ((attr_ptr == NULL) || (waiting_protocol_ptr == NULL))
{
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
return (MQX_EINVAL);
} /* Endif */
#endif
*waiting_protocol_ptr = attr_ptr->WAIT_PROTOCOL;
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Gets the priority ceiling from a mutex attributes structure.
*
* Priority applies only to mutexes whose scheduling protocol is priority protect.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[out] ceiling_ptr Pointer to the current priority.
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
*
* \see _mutatr_set_priority_ceiling
* \see _mutatr_init
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_get_priority_ceiling
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint_ptr ceiling_ptr
)
{ /* Body */
#if MQX_CHECK_ERRORS
if ((attr_ptr == NULL) || (ceiling_ptr == NULL))
{
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
return (MQX_EINVAL);
} /* Endif */
#endif
*ceiling_ptr = attr_ptr->PRIORITY_CEILING;
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Gets the scheduling protocol of the mutex attributes structure.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[out] protocol_ptr Pointer to the current scheduling protocol.
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
*
* \see _mutatr_set_sched_protocol
* \see _mutatr_init
* \see _mutatr_get_priority_ceiling
* \see _mutatr_set_priority_ceiling
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_get_sched_protocol
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint_ptr protocol_ptr
)
{ /* Body */
#if MQX_CHECK_ERRORS
if ((attr_ptr == NULL) || (protocol_ptr == NULL))
{
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
return (MQX_EINVAL);
} /* Endif */
#endif
*protocol_ptr = attr_ptr->SCHED_PROTOCOL;
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Gets the spin limit of the mutex attributes structure.
*
* Spin limit applies only to mutexes whose waiting policy is limited spin. Spin
* limit is the number of times that a task spins (is rescheduled) while it waits
* for the mutex.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[out] spin_count_ptr Pointer to the current spin limit.
*
* \return MQX_OK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
*
* \see _mutatr_set_spin_limit
* \see _mutatr_init
* \see _mutatr_get_wait_protocol
* \see _mutatr_set_wait_protocol
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_get_spin_limit
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint_ptr spin_count_ptr
)
{ /* Body */
#if MQX_CHECK_ERRORS
if ((attr_ptr == NULL) || (spin_count_ptr == NULL))
{
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
return (MQX_EINVAL);
} /* Endif */
#endif
*spin_count_ptr = attr_ptr->COUNT;
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Initializes the mutex.
*
* \param[in] mutex_ptr Pointer to where the mutex is to be initialized.
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure or
* NULL (use default attributes as defined for _mutatr_init()).
*
* \return MQX_EOK
* \return MQX_EINVAL (Mutex_ptr is NULL, attr_ptr is not initialized or a value
* in attr_ptr is not correct.)
* \return MQX_INVALID_COMPONENT_BASE (Mutex component data is not valid.)
* \return MQX_OUT_OF_MEMORY
*
* \warning Creates the mutex component if it was not previously created.
*
* \see _mutex_destroy
* \see _mutatr_init
* \see MUTEX_STRUCT
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutex_init
(
register MUTEX_STRUCT_PTR mutex_ptr,
register MUTEX_ATTR_STRUCT_PTR attr_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
MUTEX_ATTR_STRUCT default_attr;
#if MQX_CHECK_ERRORS
MUTEX_STRUCT_PTR mutex_chk_ptr;
#endif
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
if (attr_ptr == NULL)
{
attr_ptr = &default_attr;
_mutatr_init(attr_ptr);
_KLOGE3(KLOG_mutex_init, mutex_ptr, NULL);
}
else
{
_KLOGE3(KLOG_mutex_init, mutex_ptr, attr_ptr);
} /* Endif */
#if MQX_CHECK_ERRORS
if (mutex_ptr == NULL)
{
_KLOGX2(KLOG_mutex_init, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_init, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
if (mutex_component_ptr == NULL)
{
result = _mutex_create_component();
mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (mutex_component_ptr == NULL)
{
_KLOGX2(KLOG_mutex_init, result);
return (result);
} /* Endif */
#endif
} /* Endif */
#if MQX_CHECK_VALIDITY
if (mutex_component_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_init, MQX_INVALID_COMPONENT_BASE);
return (MQX_INVALID_COMPONENT_BASE);
} /* Endif */
#endif
_int_disable();
#if MQX_CHECK_ERRORS
/* Check if mutex is already initialized */
mutex_chk_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_component_ptr->MUTEXES.NEXT);
while (mutex_chk_ptr != (MUTEX_STRUCT_PTR) ((pointer) &mutex_component_ptr->MUTEXES))
{
if (mutex_chk_ptr == mutex_ptr)
{
_int_enable();
_KLOGX2(KLOG_mutex_init, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
mutex_chk_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_chk_ptr->LINK.NEXT);
} /* Endif */
#endif
mutex_ptr->PROTOCOLS = attr_ptr->SCHED_PROTOCOL | attr_ptr->WAIT_PROTOCOL;
mutex_ptr->VALID = MUTEX_VALID;
mutex_ptr->COUNT = attr_ptr->COUNT;
mutex_ptr->PRIORITY_CEILING = attr_ptr->PRIORITY_CEILING;
mutex_ptr->LOCK = 0;
mutex_ptr->BOOSTED = 0;
mutex_ptr->OWNER_TD = NULL;
_QUEUE_INIT(&mutex_ptr->WAITING_TASKS, 0);
_QUEUE_ENQUEUE(&mutex_component_ptr->MUTEXES, mutex_ptr);
_int_enable();
_KLOGX2(KLOG_mutex_init, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Locks the mutex.
*
* If the mutex is already locked, the task waits according to the waiting protocol
* of the mutex.
*
* \param[in] mutex_ptr Pointer to the mutex to be locked.
*
* \return MQX_EOK
* \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
* \return MQX_EINVAL (Mutex_ptr is NULL or mutex was destroyed.)
* \return MQX_EDEADLK (Task already has the mutex locked.)
* \return MQX_EBUSY (Mutex is already locked.)
*
* \warning Might block the calling task.
* \warning Cannot be called from an ISR.
*
* \see _mutex_init
* \see _mutex_try_lock
* \see _mutex_unlock
* \see _mutatr_init
* \see _mutatr_get_wait_protocol
* \see _mutatr_set_wait_protocol
* \see _mutex_destroy
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_lock
(
register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
register KERNEL_DATA_STRUCT_PTR kernel_data;
register TD_STRUCT_PTR td_ptr;
volatile uchar _PTR_ lock_ptr;
_mqx_uint priority;
_mqx_uint count;
#if MQX_MUTEX_HAS_POLLING
_mqx_uint limited;
#endif
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mutex_lock, mutex_ptr);
td_ptr = kernel_data->ACTIVE_PTR;
#if MQX_CHECK_ERRORS
if (kernel_data->IN_ISR)
{
_KLOGX2(KLOG_mutex_lock, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
} /* Endif */
if (mutex_ptr == NULL)
{
_KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mutex_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
if (mutex_ptr->OWNER_TD == (pointer) td_ptr)
{
_KLOGX2(KLOG_mutex_lock, MQX_EDEADLK);
return (MQX_EDEADLK);
} /* Endif */
priority = td_ptr->MY_QUEUE->PRIORITY;
lock_ptr = &mutex_ptr->LOCK;
#if MQX_MUTEX_HAS_POLLING
if ((mutex_ptr->PROTOCOLS & MUTEX_SPIN_ONLY) ||
(mutex_ptr->PROTOCOLS & MUTEX_LIMITED_SPIN))
{
if (mutex_ptr->PROTOCOLS & MUTEX_SPIN_ONLY)
{
count = 1;
limited = 0;
}
else
{
count = mutex_ptr->COUNT;
limited = 1;
} /* Endif */
if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_INHERIT)
{
_INT_DISABLE();
while (count && *lock_ptr)
{
count -= limited;
if (((TD_STRUCT_PTR)(mutex_ptr->OWNER_TD))->HOME_QUEUE->PRIORITY >
priority)
{
if (((TD_STRUCT_PTR)(mutex_ptr->OWNER_TD))->MY_QUEUE->PRIORITY >
priority)
{
_sched_boost_priority_internal(
(TD_STRUCT_PTR)mutex_ptr->OWNER_TD, priority);
} /* Endif */
mutex_ptr->BOOSTED++;
} /* Endif */
_INT_ENABLE(); /* Allow interruption and tasks of same prio a kick*/
_sched_yield();
_INT_DISABLE();
#if MQX_COMPONENT_DESTRUCTION
if (mutex_ptr->VALID != MUTEX_VALID)
{
_int_enable();
_KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
return(MQX_EINVAL);
} /* Endif */
#endif
} /* Endwhile */
if (count)
{
/* Test and set sets the high bit. */
mutex_ptr->LOCK = MQX_TEST_AND_SET_VALUE;
} /* Endif */
_INT_ENABLE();
}
else
{
while (count && _mem_test_and_set((uchar_ptr)lock_ptr))
{
count -= limited;
_sched_yield();
#if MQX_COMPONENT_DESTRUCTION
if (mutex_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
return(MQX_EINVAL);
} /* Endif */
#endif
} /* Endwhile */
} /* Endif */
if (count == 0)
{
_KLOGX2(KLOG_mutex_lock, MQX_EBUSY);
return(MQX_EBUSY);
} /* Endif */
mutex_ptr->OWNER_TD = td_ptr;
}
else
{
#endif
_INT_DISABLE();
if (*lock_ptr)
{
/* Must wait for a mutex to become available */
/* Boost the priority of the owner task if necessary */
if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_INHERIT) {
if (((TD_STRUCT_PTR) (mutex_ptr->OWNER_TD))->HOME_QUEUE->PRIORITY > priority)
{
if (((TD_STRUCT_PTR) (mutex_ptr->OWNER_TD))->MY_QUEUE->PRIORITY > priority)
{
_sched_boost_priority_internal((TD_STRUCT_PTR) mutex_ptr->OWNER_TD, priority);
} /* Endif */
mutex_ptr->BOOSTED++;
} /* Endif */
} /* Endif */
_QUEUE_UNLINK(td_ptr); /* Remove from ready to run queue */
td_ptr->INFO = (_mqx_uint) &mutex_ptr->WAITING_TASKS;
if (mutex_ptr->PROTOCOLS & MUTEX_PRIORITY_QUEUEING)
{
/*
** The waiting task must be inserted into the waiting list in order
** of the priority of the waiting task.
*/
_sched_insert_priorityq_internal(&mutex_ptr->WAITING_TASKS, td_ptr);
}
else
{
/* Enqueue at end */
_QUEUE_ENQUEUE(&mutex_ptr->WAITING_TASKS, td_ptr);
} /* Endif */
/* Now put the task to sleep */
td_ptr->STATE = MUTEX_BLOCKED;
_sched_execute_scheduler_internal();
/* If mutex alive, then active task owns it now, (done by unlock) */
#if MQX_COMPONENT_DESTRUCTION
if (mutex_ptr->VALID != MUTEX_VALID)
{
_int_enable();
_KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
}
else
{
/* Test and set sets the high bit. */
mutex_ptr->LOCK = MQX_TEST_AND_SET_VALUE;
mutex_ptr->OWNER_TD = td_ptr;
} /* Endif */
/*
* This task now owns the mutex, if priority inheritance is in effect
* the queue of waiting tasks must be checked for any task which may
* have a higher priority than mine ONLY if priority queueing is NOT
* in effect
*/
if ((mutex_ptr->PROTOCOLS & MUTEX_PRIO_INHERIT) && !(mutex_ptr->PROTOCOLS & MUTEX_PRIORITY_QUEUEING))
{
count = _sched_get_max_priority_on_q_internal(&mutex_ptr->WAITING_TASKS);
if (count < td_ptr->HOME_QUEUE->PRIORITY)
{
if (count < td_ptr->MY_QUEUE->PRIORITY)
{
_sched_boost_priority_internal(td_ptr, count);
} /* Endif */
mutex_ptr->BOOSTED++;
} /* Endif */
} /* Endif */
_INT_ENABLE();
#if MQX_MUTEX_HAS_POLLING
} /* Endif */
#endif
if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_PROTECT)
{
/* Switch my priority to the higher one if necessary */
_INT_DISABLE();
if (mutex_ptr->PRIORITY_CEILING < td_ptr->HOME_QUEUE->PRIORITY)
{
if (mutex_ptr->PRIORITY_CEILING < td_ptr->MY_QUEUE->PRIORITY)
{
_sched_boost_priority_internal(td_ptr, mutex_ptr->PRIORITY_CEILING);
} /* Endif */
mutex_ptr->BOOSTED++;
} /* Endif */
_INT_ENABLE();
} /* Endif */
_KLOGX2(KLOG_mutex_lock, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Sets the waiting policy of the mutex attributes structure.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[in] waiting_protocol New waiting protocol (see waiting protocols).
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attribute structure.)
*
* \see _mutatr_get_wait_protocol
* \see _mutatr_init
* \see _mutatr_get_spin_limit
* \see _mutatr_set_spin_limit
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_set_wait_protocol
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint waiting_protocol
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE3(KLOG_mutatr_set_wait_protocol, attr_ptr, waiting_protocol);
#if MQX_CHECK_ERRORS
if (attr_ptr == NULL)
{
_KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_ERRORS
/* Validate input value */
if (!(
#if MQX_MUTEX_HAS_POLLING
(waiting_protocol == MUTEX_SPIN_ONLY) ||
(waiting_protocol == MUTEX_LIMITED_SPIN) ||
#endif
(waiting_protocol == MUTEX_QUEUEING) || (waiting_protocol == MUTEX_PRIORITY_QUEUEING)))
{
_KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
attr_ptr->WAIT_PROTOCOL = waiting_protocol;
_KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Sets the priority ceiling of a mutex attributes structure.
*
* Priority applies only to mutexes whose scheduling protocol is priority protect.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[in] ceiling New priority ceiling to use.
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attribute structure.)
*
* \see _mutatr_get_priority_ceiling
* \see _mutatr_init
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_set_priority_ceiling
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint ceiling
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_GET_KERNEL_DATA(kernel_data);
_KLOGE3(KLOG_mutatr_set_priority_ceiling, attr_ptr, ceiling);
#if MQX_CHECK_ERRORS
if (attr_ptr == NULL)
{
_KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_ERRORS
if (ceiling > kernel_data->LOWEST_TASK_PRIORITY)
{
_KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
attr_ptr->PRIORITY_CEILING = ceiling;
_KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Sets the scheduling protocol of the mutex attributes structure.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[in] protocol New scheduling protocol (see scheduling protocols).
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
*
* \see _mutatr_get_sched_protocol
* \see _mutatr_init
* \see _mutatr_get_priority_ceiling
* \see _mutatr_set_priority_ceiling
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_set_sched_protocol
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint protocol
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE3(KLOG_mutatr_set_sched_protocol, attr_ptr, protocol);
#if MQX_CHECK_ERRORS
if (attr_ptr == NULL)
{
_KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_ERRORS
/* Validate protocol value */
if (!((protocol == MUTEX_PRIO_INHERIT) || (protocol == MUTEX_PRIO_PROTECT) || (protocol == MUTEX_NO_PRIO_INHERIT)))
{
_KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
attr_ptr->SCHED_PROTOCOL = protocol;
_KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Sets the spin limit of the mutex attributes structure.
*
* Spin limit applies only to mutexes whose waiting policy is limited spin. Spin
* limit is the number of times that a task spins (is rescheduled) while it waits
* for the mutex.
*
* \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
* \param[in] spin_count New spin limit.
*
* \return MQX_EOK
* \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
*
* \see _mutatr_get_spin_limit
* \see _mutatr_init
* \see _mutatr_get_wait_protocol
* \see _mutatr_set_wait_protocol
* \see MUTEX_ATTR_STRUCT
*/
_mqx_uint _mutatr_set_spin_limit
(
MUTEX_ATTR_STRUCT_PTR attr_ptr,
_mqx_uint spin_count
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE3(KLOG_mutatr_set_spin_limit, attr_ptr, spin_count);
#if MQX_MUTEX_HAS_POLLING
#if MQX_CHECK_ERRORS
if (attr_ptr == NULL)
{
_KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EINVAL);
return(MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (attr_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EINVAL);
return(MQX_EINVAL);
} /* Endif */
#endif
attr_ptr->COUNT = spin_count;
_KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EOK);
return(MQX_EOK);
#else
_KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EINVAL);
return (MQX_EINVAL);
#endif
} /* Endbody */
/*!
* \brief Used during task destruction to free up any mutex owned by this task.
*
* \param[in] td_ptr Pointer to the task descriptor of the task to be destroyed.
*
* \see mutex_destroy
*/
void _mutex_cleanup
(
TD_STRUCT_PTR td_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
MUTEX_STRUCT_PTR mutex_ptr;
_GET_KERNEL_DATA(kernel_data);
mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
if (mutex_component_ptr == NULL)
{
return; /* No work to do! */
} /* Endif */
#if MQX_CHECK_VALIDITY
if (mutex_component_ptr->VALID != MUTEX_VALID)
{
return;
} /* Endif */
#endif
_int_disable();
mutex_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_component_ptr->MUTEXES.NEXT);
while (mutex_ptr != (MUTEX_STRUCT_PTR) ((pointer) &mutex_component_ptr->MUTEXES))
{
if ((mutex_ptr->LOCK) && (mutex_ptr->OWNER_TD == td_ptr))
{
mutex_ptr->OWNER_TD = kernel_data->ACTIVE_PTR;
_mutex_unlock(mutex_ptr);
mutex_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_component_ptr->MUTEXES.NEXT);
}
else
{
mutex_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_ptr->LINK.NEXT);
} /* Endif */
} /* Endwhile */
_int_enable();
} /* Endbody */
/*!
* \brief Tests the mutex component.
*
* This function tests:
* \n - mutex component data
* \n - MQX queue of mutexes
* \n - each mutex
* \n - waiting queue of each mutex
*
* \param[out] mutex_error_ptr Pointer to the invalid queue or to the mutex with the
* error (see return).
*
* \return MQX_OK No errors were found (mutex_error_ptr = NULL).
* \return MQX_INVALID_COMPONENT_BASE Mutex component data is not valid (mutex_error_ptr
* = NULL).
* \return MQX_EINVAL A mutex is not valid or a mutex queue is not valid (mutex_error_ptr
* = pointer to the mutex with the error).
* \return MQX_CORRUPT_QUEUE Queue of mutexes is not valid (mutex_error_ptr = pointer
* to the invalid queue).
*
* \see _mutex_create_component
* \see _mutex_init
*/
_mqx_uint _mutex_test
(
pointer _PTR_ mutex_error_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
MUTEX_STRUCT_PTR mutex_ptr;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mutex_test, mutex_error_ptr);
*mutex_error_ptr = NULL;
mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
if (mutex_component_ptr == NULL)
{
_KLOGX2(KLOG_mutex_test, MQX_OK);
return (MQX_OK);
} /* Endif */
if (mutex_component_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_test, MQX_INVALID_COMPONENT_BASE);
return (MQX_INVALID_COMPONENT_BASE);
} /* Endif */
_int_disable();
/* Make sure that the queue of mutexes is ok */
result = _queue_test(&mutex_component_ptr->MUTEXES, mutex_error_ptr);
if (result != MQX_OK)
{
_int_enable();
_KLOGX3(KLOG_mutex_test, result, *mutex_error_ptr);
return (result);
} /* Endif */
mutex_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_component_ptr->MUTEXES.NEXT);
while (mutex_ptr != (MUTEX_STRUCT_PTR) ((pointer) &mutex_component_ptr->MUTEXES))
{
if (mutex_ptr->VALID != MUTEX_VALID)
{
_int_enable();
*mutex_error_ptr = mutex_ptr;
_KLOGX3(KLOG_mutex_test, MQX_EINVAL, mutex_ptr);
return (MQX_EINVAL);
} /* Endif */
result = _queue_test(&mutex_ptr->WAITING_TASKS, mutex_error_ptr);
if (result != MQX_OK)
{
_int_enable();
*mutex_error_ptr = mutex_ptr;
_KLOGX3(KLOG_mutex_test, result, mutex_ptr);
return (result);
} /* Endif */
mutex_ptr = (MUTEX_STRUCT_PTR) ((pointer) mutex_ptr->LINK.NEXT);
} /* Endif */
_int_enable();
_KLOGX2(KLOG_mutex_test, MQX_OK);
return (MQX_OK);
} /* Endbody */
/*!
* \brief Tries to lock the mutex.
*
* If the mutex is not currently locked, the task locks it. If the mutex is currently
* locked, the task continues to run; it does not block.
*
* \param[in] mutex_ptr Pointer to the mutex.
*
* \return MQX_EOK
* \return MQX_EBUSY (Mutex is currently locked.)
* \return MQX_EDEADLK (Task already has the mutex locked.)
* \return MQX_EINVAL (Mutex_ptr is NULL or mutex has been destroyed.)
*
* \see _mutex_create_component
* \see _mutex_init
* \see _mutex_lock
* \see _mutex_unlock
* \see _mutatr_init
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_try_lock
(
register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
TD_STRUCT_PTR td_ptr;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mutex_try_lock, mutex_ptr);
#if MQX_CHECK_ERRORS
if (mutex_ptr == NULL)
{
_KLOGX2(KLOG_mutex_try_lock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mutex_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_try_lock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
_INT_DISABLE();
if (_mem_test_and_set(&mutex_ptr->LOCK))
{
_INT_ENABLE();
/* Lock value was set, can't have it */
if (mutex_ptr->OWNER_TD == (pointer) kernel_data->ACTIVE_PTR)
{
_KLOGX2(KLOG_mutex_try_lock, MQX_EDEADLK);
return (MQX_EDEADLK);
}
else
{
_KLOGX2(KLOG_mutex_try_lock, MQX_EBUSY);
return (MQX_EBUSY);
} /* Endif */
}
else
{
/* Lock value was not set, now it is, I own it */
mutex_ptr->OWNER_TD = kernel_data->ACTIVE_PTR;
_INT_ENABLE();
if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_PROTECT)
{
/* Switch my priority to the higher one if necessary */
td_ptr = kernel_data->ACTIVE_PTR;
_INT_DISABLE();
if (mutex_ptr->PRIORITY_CEILING < td_ptr->HOME_QUEUE->PRIORITY)
{
if (mutex_ptr->PRIORITY_CEILING < td_ptr->MY_QUEUE->PRIORITY)
{
_sched_boost_priority_internal(td_ptr, mutex_ptr->PRIORITY_CEILING);
} /* Endif */
mutex_ptr->BOOSTED++;
} /* Endif */
_INT_ENABLE();
} /* Endif */
_KLOGX2(KLOG_mutex_try_lock, MQX_EOK);
return (MQX_EOK);
} /* Endif */
} /* Endbody */
/*!
* \brief Unlocks the mutex.
*
* If tasks are waiting for the mutex, MQX removes the first one from the mutex
* queue and puts the task in the task's ready queue.
*
* \param[in] mutex_ptr Pointer to the mutex.
*
* \return MQX_EOK
* \return MQX_EINVAL
*
* \warning Might put a task in the task's ready queue.
*
* \see _mutex_create_component
* \see _mutex_init
* \see _mutex_lock
* \see _mutex_try_lock
* \see _mutatr_init
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_unlock
(
register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
register KERNEL_DATA_STRUCT_PTR kernel_data;
register TD_STRUCT_PTR td_ptr;
_mqx_uint boosted;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mutex_unlock, mutex_ptr);
td_ptr = kernel_data->ACTIVE_PTR;
#if MQX_CHECK_ERRORS
if (mutex_ptr == NULL)
{
_KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mutex_ptr->VALID != MUTEX_VALID)
{
_KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_ERRORS
if (mutex_ptr->LOCK != MQX_TEST_AND_SET_VALUE)
{
_KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
if (mutex_ptr->OWNER_TD != (pointer) td_ptr)
{
_KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
_INT_DISABLE();
boosted = mutex_ptr->BOOSTED;
mutex_ptr->BOOSTED = 0;
if (mutex_ptr->PROTOCOLS & (MUTEX_SPIN_ONLY | MUTEX_LIMITED_SPIN))
{
mutex_ptr->OWNER_TD = NULL;
mutex_ptr->LOCK = 0;
}
else
{
if (_QUEUE_GET_SIZE(&mutex_ptr->WAITING_TASKS))
{
/* Schedule a waiting task to run */
_QUEUE_DEQUEUE(&mutex_ptr->WAITING_TASKS, td_ptr);
mutex_ptr->OWNER_TD = td_ptr;
_TASK_READY(td_ptr, kernel_data);
if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_PROTECT)
{
/* Switch priority to the higher one if necessary */
if (mutex_ptr->PRIORITY_CEILING < td_ptr->HOME_QUEUE->PRIORITY)
{
if (mutex_ptr->PRIORITY_CEILING < td_ptr->MY_QUEUE->PRIORITY)
{
_sched_boost_priority_internal(td_ptr, mutex_ptr->PRIORITY_CEILING);
} /* Endif */
mutex_ptr->BOOSTED++;
} /* Endif */
} /* Endif */
_CHECK_RUN_SCHEDULER();/* Let higher priority task run */
}
else
{
mutex_ptr->LOCK = 0;
mutex_ptr->OWNER_TD = NULL;
} /* Endif */
} /* Endif */
if (boosted)
{
_sched_unboost_priority_internal(kernel_data->ACTIVE_PTR, boosted);
} /* Endif */
_INT_ENABLE();
_KLOGX2(KLOG_mutex_unlock, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Sets the priority of the mutex.
*
* This function operate on an initialized mutex; whereas, _mutatr_get_priority_ceiling()
* and _mutatr_set_priority_ceiling() operate on an initialized mutex attributes
* structure.
*
* \param[in] mutex_ptr Pointer to the mutex.
* \param[in] ceiling New priority ceiling.
* \param[out] old_ceiling_ptr Pointer to the previous priority ceiling.
*
* \return MQX_EOK
* \return MQX_EINVAL (Mutex_ptr does not point to a valid mutex structure or
* priority_ptr is NULL)
*
* \see _mutex_get_priority_ceiling
* \see _mutex_init
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_set_priority_ceiling
(
MUTEX_STRUCT_PTR mutex_ptr,
_mqx_uint ceiling,
_mqx_uint_ptr old_ceiling_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_GET_KERNEL_DATA(kernel_data);
_KLOGE4(KLOG_mutex_set_priority_ceiling, mutex_ptr, ceiling, old_ceiling_ptr);
#if MQX_CHECK_ERRORS
if (ceiling > kernel_data->LOWEST_TASK_PRIORITY)
{
_KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
_int_disable();
#if MQX_CHECK_ERRORS
if ((mutex_ptr == NULL) || (old_ceiling_ptr == NULL))
{
_int_enable();
_KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mutex_ptr->VALID != MUTEX_VALID)
{
_int_enable();
_KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EINVAL);
return (MQX_EINVAL);
} /* Endif */
#endif
*old_ceiling_ptr = mutex_ptr->PRIORITY_CEILING;
mutex_ptr->PRIORITY_CEILING = ceiling;
_int_enable();
_KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EOK);
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Gets the priority of the mutex.
*
* This function operate on an initialized mutex; whereas, _mutatr_get_priority_ceiling()
* and _mutatr_set_priority_ceiling() operate on an initialized mutex attributes
* structure.
*
* \param[in] mutex_ptr Pointer to the mutex.
* \param[out] ceiling_ptr Pointer to the previous priority ceiling.
*
* \return MQX_EOK
* \return MQX_EINVAL (Mutex_ptr does not point to a valid mutex structure or
* priority_ptr is NULL)
*
* \see _mutex_set_priority_ceiling
* \see _mutex_init
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_get_priority_ceiling
(
MUTEX_STRUCT_PTR mutex_ptr,
_mqx_uint_ptr ceiling_ptr
)
{ /* Body */
#if MQX_CHECK_ERRORS
if ((mutex_ptr == NULL) || (ceiling_ptr == NULL))
{
return (MQX_EINVAL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mutex_ptr->VALID != MUTEX_VALID)
{
return (MQX_EINVAL);
} /* Endif */
#endif
*ceiling_ptr = mutex_ptr->PRIORITY_CEILING;
return (MQX_EOK);
} /* Endbody */
/*!
* \brief Gets the number of tasks waiting for the specified mutex.
*
* \param[in] mutex_ptr Pointer to the mutex.
*
* \return Number of tasks that are waiting for the mutex.
* \return MAX_MQX_UINT (Failure.)
*
* \warning On failure, calls _task_set_error() to set the task error code to
* MQX_EINVAL.
*
* \see _mutex_lock
* \see _task_set_error
* \see MUTEX_STRUCT
*/
_mqx_uint _mutex_get_wait_count
(
register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
#if MQX_CHECK_ERRORS
if (mutex_ptr == NULL)
{
_task_set_error(MQX_EINVAL);
return (MAX_MQX_UINT);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mutex_ptr->VALID != MUTEX_VALID)
{
_task_set_error(MQX_EINVAL);
return (MAX_MQX_UINT);
} /* Endif */
#endif
return (_QUEUE_GET_SIZE(&mutex_ptr->WAITING_TASKS));
} /* Endbody */
#endif /* MQX_USE_MUTEXES */
/* EOF */