/*
 * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * -----------------------------------------------------------------------------
 *
 * Project:     CMSIS-RTOS RTX
 * Title:       Memory Pool functions
 *
 * -----------------------------------------------------------------------------
 */

#include "rtx_lib.h"

//  OS Runtime Object Memory Usage
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
osRtxObjectMemUsage_t osRtxMemoryPoolMemUsage
    __attribute__((section(".data.os.mempool.obj"))) = {0U, 0U, 0U};
#endif

//  ==== Library functions ====

/// Initialize Memory Pool.
/// \param[in]  mp_info         memory pool info.
/// \param[in]  block_count     maximum number of memory blocks in memory pool.
/// \param[in]  block_size      size of a memory block in bytes.
/// \param[in]  block_mem       pointer to memory for block storage.
/// \return 1 - success, 0 - failure.
uint32_t osRtxMemoryPoolInit(os_mp_info_t *mp_info, uint32_t block_count,
                             uint32_t block_size, void *block_mem) {
  // lint --e{9079} --e{9087} "conversion from pointer to void to pointer to
  // other type" [MISRA Note 6]
  void *mem;
  void *block;

  // Check parameters
  if ((mp_info == NULL) || (block_count == 0U) || (block_size == 0U) ||
      (block_mem == NULL)) {
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  // Initialize information structure
  mp_info->max_blocks = block_count;
  mp_info->used_blocks = 0U;
  mp_info->block_size = block_size;
  mp_info->block_base = block_mem;
  mp_info->block_free = block_mem;
  mp_info->block_lim = &(((uint8_t *)block_mem)[block_count * block_size]);

  EvrRtxMemoryBlockInit(mp_info, block_count, block_size, block_mem);

  // Link all free blocks
  mem = block_mem;
  while (--block_count != 0U) {
    block = &((uint8_t *)mem)[block_size];
    *((void **)mem) = block;
    mem = block;
  }
  *((void **)mem) = NULL;

  return 1U;
}

/// Allocate a memory block from a Memory Pool.
/// \param[in]  mp_info         memory pool info.
/// \return address of the allocated memory block or NULL in case of no memory
/// is available.
void *osRtxMemoryPoolAlloc(os_mp_info_t *mp_info) {
#if (EXCLUSIVE_ACCESS == 0)
  uint32_t primask = __get_PRIMASK();
#endif
  void *block;

  if (mp_info == NULL) {
    EvrRtxMemoryBlockAlloc(NULL, NULL);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }

#if (EXCLUSIVE_ACCESS == 0)
  __disable_irq();

  block = mp_info->block_free;
  if (block != NULL) {
    // lint --e{9079} --e{9087} "conversion from pointer to void to pointer to
    // other type"
    mp_info->block_free = *((void **)block);
    mp_info->used_blocks++;
  }

  if (primask == 0U) {
    __enable_irq();
  }
#else
  block = atomic_link_get(&mp_info->block_free);
  if (block != NULL) {
    (void)atomic_inc32(&mp_info->used_blocks);
  }
#endif

  EvrRtxMemoryBlockAlloc(mp_info, block);

  return block;
}

/// Return an allocated memory block back to a Memory Pool.
/// \param[in]  mp_info         memory pool info.
/// \param[in]  block           address of the allocated memory block to be
/// returned to the memory pool. \return status code that indicates the
/// execution status of the function.
osStatus_t osRtxMemoryPoolFree(os_mp_info_t *mp_info, void *block) {
#if (EXCLUSIVE_ACCESS == 0)
  uint32_t primask = __get_PRIMASK();
#endif

  // lint -e{946} "Relational operator applied to pointers"
  if ((mp_info == NULL) || (block < mp_info->block_base) ||
      (block >= mp_info->block_lim)) {
    EvrRtxMemoryBlockFree(mp_info, block, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return osErrorParameter;
  }

#if (EXCLUSIVE_ACCESS == 0)
  __disable_irq();

  // lint --e{9079} --e{9087} "conversion from pointer to void to pointer to
  // other type"
  *((void **)block) = mp_info->block_free;
  mp_info->block_free = block;
  mp_info->used_blocks--;

  if (primask == 0U) {
    __enable_irq();
  }
#else
  atomic_link_put(&mp_info->block_free, block);
  (void)atomic_dec32(&mp_info->used_blocks);
#endif

  EvrRtxMemoryBlockFree(mp_info, block, (int32_t)osOK);

  return osOK;
}

//  ==== Post ISR processing ====

/// Memory Pool post ISR processing.
/// \param[in]  mp              memory pool object.
static void osRtxMemoryPoolPostProcess(os_memory_pool_t *mp) {
  void *block;
  os_thread_t *thread;

  // Check if Thread is waiting to allocate memory
  if (mp->thread_list != NULL) {
    // Allocate memory
    block = osRtxMemoryPoolAlloc(&mp->mp_info);
    if (block != NULL) {
      // Wakeup waiting Thread with highest Priority
      thread = osRtxThreadListGet(osRtxObject(mp));
      // lint -e{923} "cast from pointer to unsigned int"
      osRtxThreadWaitExit(thread, (uint32_t)block, FALSE);
      EvrRtxMemoryPoolAllocated(mp, block);
    }
  }
}

//  ==== Service Calls ====

/// Create and Initialize a Memory Pool object.
/// \note API identical to osMemoryPoolNew
static osMemoryPoolId_t svcRtxMemoryPoolNew(uint32_t block_count,
                                            uint32_t block_size,
                                            const osMemoryPoolAttr_t *attr) {
  os_memory_pool_t *mp;
  void *mp_mem;
  uint32_t mp_size;
  uint32_t b_count;
  uint32_t b_size;
  uint32_t size;
  uint8_t flags;
  const char *name;

  // Check parameters
  if ((block_count == 0U) || (block_size == 0U)) {
    EvrRtxMemoryPoolError(NULL, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }
  b_count = block_count;
  b_size = (block_size + 3U) & ~3UL;
  if ((__CLZ(b_count) + __CLZ(b_size)) < 32U) {
    EvrRtxMemoryPoolError(NULL, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }

  size = b_count * b_size;

  // Process attributes
  if (attr != NULL) {
    name = attr->name;
    // lint -e{9079} "conversion from pointer to void to pointer to other type"
    // [MISRA Note 6]
    mp = attr->cb_mem;
    // lint -e{9079} "conversion from pointer to void to pointer to other type"
    // [MISRA Note 6]
    mp_mem = attr->mp_mem;
    mp_size = attr->mp_size;
    if (mp != NULL) {
      // lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note
      // 7]
      if ((((uint32_t)mp & 3U) != 0U) ||
          (attr->cb_size < sizeof(os_memory_pool_t))) {
        EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidControlBlock);
        // lint -e{904} "Return statement before end of function" [MISRA Note 1]
        return NULL;
      }
    } else {
      if (attr->cb_size != 0U) {
        EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidControlBlock);
        // lint -e{904} "Return statement before end of function" [MISRA Note 1]
        return NULL;
      }
    }
    if (mp_mem != NULL) {
      // lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note
      // 7]
      if ((((uint32_t)mp_mem & 3U) != 0U) || (mp_size < size)) {
        EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidDataMemory);
        // lint -e{904} "Return statement before end of function" [MISRA Note 1]
        return NULL;
      }
    } else {
      if (mp_size != 0U) {
        EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidDataMemory);
        // lint -e{904} "Return statement before end of function" [MISRA Note 1]
        return NULL;
      }
    }
  } else {
    name = NULL;
    mp = NULL;
    mp_mem = NULL;
  }

  // Allocate object memory if not provided
  if (mp == NULL) {
    if (osRtxInfo.mpi.memory_pool != NULL) {
      // lint -e{9079} "conversion from pointer to void to pointer to other
      // type" [MISRA Note 5]
      mp = osRtxMemoryPoolAlloc(osRtxInfo.mpi.memory_pool);
    } else {
      // lint -e{9079} "conversion from pointer to void to pointer to other
      // type" [MISRA Note 5]
      mp = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_memory_pool_t), 1U);
    }
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
    if (mp != NULL) {
      uint32_t used;
      osRtxMemoryPoolMemUsage.cnt_alloc++;
      used =
          osRtxMemoryPoolMemUsage.cnt_alloc - osRtxMemoryPoolMemUsage.cnt_free;
      if (osRtxMemoryPoolMemUsage.max_used < used) {
        osRtxMemoryPoolMemUsage.max_used = used;
      }
    }
#endif
    flags = osRtxFlagSystemObject;
  } else {
    flags = 0U;
  }

  // Allocate data memory if not provided
  if ((mp != NULL) && (mp_mem == NULL)) {
    // lint -e{9079} "conversion from pointer to void to pointer to other type"
    // [MISRA Note 5]
    mp_mem = osRtxMemoryAlloc(osRtxInfo.mem.mp_data, size, 0U);
    if (mp_mem == NULL) {
      if ((flags & osRtxFlagSystemObject) != 0U) {
        if (osRtxInfo.mpi.memory_pool != NULL) {
          (void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
        } else {
          (void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
        }
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
        osRtxMemoryPoolMemUsage.cnt_free++;
#endif
      }
      mp = NULL;
    } else {
      memset(mp_mem, 0, size);
    }
    flags |= osRtxFlagSystemMemory;
  }

  if (mp != NULL) {
    // Initialize control block
    mp->id = osRtxIdMemoryPool;
    mp->flags = flags;
    mp->name = name;
    mp->thread_list = NULL;
    (void)osRtxMemoryPoolInit(&mp->mp_info, b_count, b_size, mp_mem);

    // Register post ISR processing function
    osRtxInfo.post_process.memory_pool = osRtxMemoryPoolPostProcess;

    EvrRtxMemoryPoolCreated(mp, mp->name);
  } else {
    EvrRtxMemoryPoolError(NULL, (int32_t)osErrorNoMemory);
  }

  return mp;
}

/// Get name of a Memory Pool object.
/// \note API identical to osMemoryPoolGetName
static const char *svcRtxMemoryPoolGetName(osMemoryPoolId_t mp_id) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolGetName(mp, NULL);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }

  EvrRtxMemoryPoolGetName(mp, mp->name);

  return mp->name;
}

/// Allocate a memory block from a Memory Pool.
/// \note API identical to osMemoryPoolAlloc
static void *svcRtxMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
  void *block;

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }

  // Allocate memory
  block = osRtxMemoryPoolAlloc(&mp->mp_info);
  if (block != NULL) {
    EvrRtxMemoryPoolAllocated(mp, block);
  } else {
    // No memory available
    if (timeout != 0U) {
      EvrRtxMemoryPoolAllocPending(mp, timeout);
      // Suspend current Thread
      if (osRtxThreadWaitEnter(osRtxThreadWaitingMemoryPool, timeout)) {
        osRtxThreadListPut(osRtxObject(mp), osRtxThreadGetRunning());
      } else {
        EvrRtxMemoryPoolAllocTimeout(mp);
      }
    } else {
      EvrRtxMemoryPoolAllocFailed(mp);
    }
  }

  return block;
}

/// Return an allocated memory block back to a Memory Pool.
/// \note API identical to osMemoryPoolFree
static osStatus_t svcRtxMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
  void *block0;
  os_thread_t *thread;
  osStatus_t status;

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return osErrorParameter;
  }

  // Free memory
  status = osRtxMemoryPoolFree(&mp->mp_info, block);
  if (status == osOK) {
    EvrRtxMemoryPoolDeallocated(mp, block);
    // Check if Thread is waiting to allocate memory
    if (mp->thread_list != NULL) {
      // Allocate memory
      block0 = osRtxMemoryPoolAlloc(&mp->mp_info);
      if (block0 != NULL) {
        // Wakeup waiting Thread with highest Priority
        thread = osRtxThreadListGet(osRtxObject(mp));
        // lint -e{923} "cast from pointer to unsigned int"
        osRtxThreadWaitExit(thread, (uint32_t)block0, TRUE);
        EvrRtxMemoryPoolAllocated(mp, block0);
      }
    }
  } else {
    EvrRtxMemoryPoolFreeFailed(mp, block);
  }

  return status;
}

/// Get maximum number of memory blocks in a Memory Pool.
/// \note API identical to osMemoryPoolGetCapacity
static uint32_t svcRtxMemoryPoolGetCapacity(osMemoryPoolId_t mp_id) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolGetCapacity(mp, 0U);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  EvrRtxMemoryPoolGetCapacity(mp, mp->mp_info.max_blocks);

  return mp->mp_info.max_blocks;
}

/// Get memory block size in a Memory Pool.
/// \note API identical to osMemoryPoolGetBlockSize
static uint32_t svcRtxMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolGetBlockSize(mp, 0U);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  EvrRtxMemoryPoolGetBlockSize(mp, mp->mp_info.block_size);

  return mp->mp_info.block_size;
}

/// Get number of memory blocks used in a Memory Pool.
/// \note API identical to osMemoryPoolGetCount
static uint32_t svcRtxMemoryPoolGetCount(osMemoryPoolId_t mp_id) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolGetCount(mp, 0U);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  EvrRtxMemoryPoolGetCount(mp, mp->mp_info.used_blocks);

  return mp->mp_info.used_blocks;
}

/// Get number of memory blocks available in a Memory Pool.
/// \note API identical to osMemoryPoolGetSpace
static uint32_t svcRtxMemoryPoolGetSpace(osMemoryPoolId_t mp_id) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolGetSpace(mp, 0U);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return 0U;
  }

  EvrRtxMemoryPoolGetSpace(mp,
                           mp->mp_info.max_blocks - mp->mp_info.used_blocks);

  return (mp->mp_info.max_blocks - mp->mp_info.used_blocks);
}

/// Delete a Memory Pool object.
/// \note API identical to osMemoryPoolDelete
static osStatus_t svcRtxMemoryPoolDelete(osMemoryPoolId_t mp_id) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
  os_thread_t *thread;

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return osErrorParameter;
  }

  // Unblock waiting threads
  if (mp->thread_list != NULL) {
    do {
      thread = osRtxThreadListGet(osRtxObject(mp));
      osRtxThreadWaitExit(thread, 0U, FALSE);
    } while (mp->thread_list != NULL);
    osRtxThreadDispatch(NULL);
  }

  // Mark object as invalid
  mp->id = osRtxIdInvalid;

  // Free data memory
  if ((mp->flags & osRtxFlagSystemMemory) != 0U) {
    (void)osRtxMemoryFree(osRtxInfo.mem.mp_data, mp->mp_info.block_base);
  }

  // Free object memory
  if ((mp->flags & osRtxFlagSystemObject) != 0U) {
    if (osRtxInfo.mpi.memory_pool != NULL) {
      (void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
    } else {
      (void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
    }
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
    osRtxMemoryPoolMemUsage.cnt_free++;
#endif
  }

  EvrRtxMemoryPoolDestroyed(mp);

  return osOK;
}

//  Service Calls definitions
// lint ++flb "Library Begin" [MISRA Note 11]
SVC0_3(MemoryPoolNew, osMemoryPoolId_t, uint32_t, uint32_t,
       const osMemoryPoolAttr_t *)
SVC0_1(MemoryPoolGetName, const char *, osMemoryPoolId_t)
SVC0_2(MemoryPoolAlloc, void *, osMemoryPoolId_t, uint32_t)
SVC0_2(MemoryPoolFree, osStatus_t, osMemoryPoolId_t, void *)
SVC0_1(MemoryPoolGetCapacity, uint32_t, osMemoryPoolId_t)
SVC0_1(MemoryPoolGetBlockSize, uint32_t, osMemoryPoolId_t)
SVC0_1(MemoryPoolGetCount, uint32_t, osMemoryPoolId_t)
SVC0_1(MemoryPoolGetSpace, uint32_t, osMemoryPoolId_t)
SVC0_1(MemoryPoolDelete, osStatus_t, osMemoryPoolId_t)
// lint --flb "Library End"

//  ==== ISR Calls ====

/// Allocate a memory block from a Memory Pool.
/// \note API identical to osMemoryPoolAlloc
__STATIC_INLINE
void *isrRtxMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
  void *block;

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool) || (timeout != 0U)) {
    EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return NULL;
  }

  // Allocate memory
  block = osRtxMemoryPoolAlloc(&mp->mp_info);
  if (block == NULL) {
    EvrRtxMemoryPoolAllocFailed(mp);
  } else {
    EvrRtxMemoryPoolAllocated(mp, block);
  }

  return block;
}

/// Return an allocated memory block back to a Memory Pool.
/// \note API identical to osMemoryPoolFree
__STATIC_INLINE
osStatus_t isrRtxMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) {
  os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
  osStatus_t status;

  // Check parameters
  if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
    EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
    // lint -e{904} "Return statement before end of function" [MISRA Note 1]
    return osErrorParameter;
  }

  // Free memory
  status = osRtxMemoryPoolFree(&mp->mp_info, block);
  if (status == osOK) {
    // Register post ISR processing
    osRtxPostProcess(osRtxObject(mp));
    EvrRtxMemoryPoolDeallocated(mp, block);
  } else {
    EvrRtxMemoryPoolFreeFailed(mp, block);
  }

  return status;
}

//  ==== Public API ====

/// Create and Initialize a Memory Pool object.
osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size,
                                 const osMemoryPoolAttr_t *attr) {
  osMemoryPoolId_t mp_id;

  EvrRtxMemoryPoolNew(block_count, block_size, attr);
  if (IsIrqMode() || IsIrqMasked()) {
    EvrRtxMemoryPoolError(NULL, (int32_t)osErrorISR);
    mp_id = NULL;
  } else {
    mp_id = __svcMemoryPoolNew(block_count, block_size, attr);
  }
  return mp_id;
}

/// Get name of a Memory Pool object.
const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id) {
  const char *name;

  if (IsIrqMode() || IsIrqMasked()) {
    EvrRtxMemoryPoolGetName(mp_id, NULL);
    name = NULL;
  } else {
    name = __svcMemoryPoolGetName(mp_id);
  }
  return name;
}

/// Allocate a memory block from a Memory Pool.
void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) {
  void *memory;

  EvrRtxMemoryPoolAlloc(mp_id, timeout);
  if (IsIrqMode() || IsIrqMasked()) {
    memory = isrRtxMemoryPoolAlloc(mp_id, timeout);
  } else {
    memory = __svcMemoryPoolAlloc(mp_id, timeout);
  }
  return memory;
}

/// Return an allocated memory block back to a Memory Pool.
osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) {
  osStatus_t status;

  EvrRtxMemoryPoolFree(mp_id, block);
  if (IsIrqMode() || IsIrqMasked()) {
    status = isrRtxMemoryPoolFree(mp_id, block);
  } else {
    status = __svcMemoryPoolFree(mp_id, block);
  }
  return status;
}

/// Get maximum number of memory blocks in a Memory Pool.
uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id) {
  uint32_t capacity;

  if (IsIrqMode() || IsIrqMasked()) {
    capacity = svcRtxMemoryPoolGetCapacity(mp_id);
  } else {
    capacity = __svcMemoryPoolGetCapacity(mp_id);
  }
  return capacity;
}

/// Get memory block size in a Memory Pool.
uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id) {
  uint32_t block_size;

  if (IsIrqMode() || IsIrqMasked()) {
    block_size = svcRtxMemoryPoolGetBlockSize(mp_id);
  } else {
    block_size = __svcMemoryPoolGetBlockSize(mp_id);
  }
  return block_size;
}

/// Get number of memory blocks used in a Memory Pool.
uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id) {
  uint32_t count;

  if (IsIrqMode() || IsIrqMasked()) {
    count = svcRtxMemoryPoolGetCount(mp_id);
  } else {
    count = __svcMemoryPoolGetCount(mp_id);
  }
  return count;
}

/// Get number of memory blocks available in a Memory Pool.
uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id) {
  uint32_t space;

  if (IsIrqMode() || IsIrqMasked()) {
    space = svcRtxMemoryPoolGetSpace(mp_id);
  } else {
    space = __svcMemoryPoolGetSpace(mp_id);
  }
  return space;
}

/// Delete a Memory Pool object.
osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id) {
  osStatus_t status;

  EvrRtxMemoryPoolDelete(mp_id);
  if (IsIrqMode() || IsIrqMasked()) {
    EvrRtxMemoryPoolError(mp_id, (int32_t)osErrorISR);
    status = osErrorISR;
  } else {
    status = __svcMemoryPoolDelete(mp_id);
  }
  return status;
}
