* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "ascend_hal.h"
#include "atomic_ref.h"
#define ATOMIC_REF_STATUS_IDLE { .info.valid = ATOMIC_INVALID, .info.value = 0 }
#define ATOMIC_REF_STATUS_REF { .info.valid = ATOMIC_VALID, .info.value = 1 }
#define ATOMIC_REF_STATUS_NO_REF { .info.valid = ATOMIC_VALID, .info.value = 0 }
void atomic_ref_init(union atomic_status *status)
{
union atomic_status ref = ATOMIC_REF_STATUS_REF;
(void)__sync_lock_test_and_set((volatile int *)&status->status, ref.status);
}
void atomic_ref_uninit(union atomic_status *status)
{
union atomic_status idle = ATOMIC_REF_STATUS_IDLE;
(void)__sync_lock_test_and_set((volatile int *)&status->status, idle.status);
}
bool atomic_ref_try_init(union atomic_status *status)
{
union atomic_status ref = ATOMIC_REF_STATUS_REF;
union atomic_status idle = ATOMIC_REF_STATUS_IDLE;
return __sync_bool_compare_and_swap((volatile int *)&status->status, idle.status, ref.status);
}
bool atomic_ref_try_uninit(union atomic_status *status)
{
union atomic_status no_ref = ATOMIC_REF_STATUS_NO_REF;
union atomic_status idle = ATOMIC_REF_STATUS_IDLE;
return __sync_bool_compare_and_swap((volatile int *)&status->status, no_ref.status, idle.status);
}
void atomic_ref_self_healing(union atomic_status *status)
{
union atomic_status cur_status;
union atomic_status idle = ATOMIC_REF_STATUS_IDLE;
cur_status.status = status->status;
if ((cur_status.info.valid == ATOMIC_INVALID) && (cur_status.info.value != 0)) {
(void)__sync_bool_compare_and_swap((volatile int *)&status->status, cur_status.status, idle.status);
}
}
static bool atomic_ref_set(union atomic_status *status, int ref)
{
union atomic_status cur_status, new_status;
do {
cur_status.status = status->status;
if (cur_status.info.valid != ATOMIC_VALID) {
return false;
}
new_status.status = cur_status.status;
new_status.info.value += ref;
} while (!__sync_bool_compare_and_swap((volatile int *)&status->status, cur_status.status, new_status.status));
return true;
}
bool atomic_ref_inc(union atomic_status *status)
{
return atomic_ref_set(status, 1);
}
bool atomic_ref_dec(union atomic_status *status)
{
return atomic_ref_set(status, -1);
}
bool atomic_ref_is_valid(union atomic_status *status)
{
return (status->info.valid == ATOMIC_VALID);
}
bool atomic_ref_is_ready_clear(union atomic_status *status)
{
union atomic_status no_ref = ATOMIC_REF_STATUS_NO_REF;
return (status->status == no_ref.status);
}
void atomic_value_init(union atomic_status *status)
{
union atomic_status init_status;
init_status.info.valid = ATOMIC_VALID;
init_status.info.value = 0;
(void)__sync_lock_test_and_set((volatile int *)&status->status, init_status.status);
}
void atomic_value_set_invalid(union atomic_status *status)
{
union atomic_status mask = { .info.valid = 0, .info.value = 0x7FFFFFFF };
(void)__sync_fetch_and_and((volatile int *)&status->status, mask.status);
}
bool atomic_value_set(union atomic_status *status, unsigned int value)
{
union atomic_status cur_status, new_status;
cur_status.status = status->status;
if (cur_status.info.valid != ATOMIC_VALID) {
return false;
}
new_status.status = cur_status.status;
new_status.info.value = value;
return __sync_bool_compare_and_swap((volatile int *)&status->status, cur_status.status, new_status.status);
}
unsigned int atomic_value_get(union atomic_status *status)
{
return status->info.value;
}
bool atomic_value_is_valid(union atomic_status *status)
{
return (status->info.valid == ATOMIC_VALID);
}