Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 : #include "ref_obj.h"
11 :
12 : #ifdef __cplusplus
13 : extern "C" {
14 : #endif
15 :
16 : #define REF_OBJ_UPDATING 0x8000000000000000UL
17 : #define TRY_LOOP_MAX 0x80000000UL
18 :
19 : typedef struct {
20 : int step;
21 : uint64_t oldValTrigger;
22 : } RefObjUpdate;
23 :
24 0 : void InitRefObj(RefObj* obj)
25 : {
26 0 : obj->refCount = 0;
27 0 : obj->obj = NULL;
28 0 : }
29 :
30 32 : static bool ObjRefCount(
31 : RefObj* obj, const RefObjUpdate* update, void (*pfnHook)(RefObj*, const void*, void*), void* appInfo,
32 : const void* usrData)
33 : {
34 : uint64_t oldVal;
35 : uint64_t newVal;
36 32 : uint64_t tryCount = 0UL;
37 32 : uint64_t perSchedYield = 0x3FFU;
38 : do {
39 32 : tryCount++;
40 32 : if ((tryCount & perSchedYield) == 0U) {
41 0 : (void)mmSchedYield();
42 : }
43 32 : oldVal = obj->refCount;
44 32 : if ((oldVal & REF_OBJ_UPDATING) != 0) {
45 0 : continue;
46 : }
47 : // 防溢出
48 32 : if (((update->step < 0) && (oldVal < (uint64_t)(0L - update->step))) ||
49 32 : ((update->step > 0) && (oldVal >= REF_OBJ_UPDATING - update->step))) {
50 0 : return false;
51 : }
52 32 : newVal = (oldVal == update->oldValTrigger) ? REF_OBJ_UPDATING : (oldVal + update->step);
53 32 : if (mmCompareAndSwap64(&obj->refCount, oldVal, newVal)) {
54 32 : if (oldVal == update->oldValTrigger) {
55 30 : pfnHook(obj, usrData, appInfo);
56 : }
57 32 : return true;
58 : }
59 0 : } while (tryCount < TRY_LOOP_MAX);
60 0 : return false;
61 : }
62 :
63 0 : static void CreateRefObjVal(RefObj* obj, const void* userData, void* fnCreateObj)
64 : {
65 : (void)userData;
66 0 : obj->obj = ((FnCreateRefObjValue)fnCreateObj)(obj);
67 0 : mmSetData64(&obj->refCount, 1);
68 0 : }
69 :
70 15 : static void CreateRefObjValWithUserData(RefObj* obj, const void* userData, void* fnCreateObj)
71 : {
72 15 : obj->obj = ((FnCreateRefObjValueWithUserData)fnCreateObj)(obj, userData);
73 15 : mmSetData64(&obj->refCount, 1);
74 15 : }
75 :
76 15 : static void DestroyRefObjVal(RefObj* obj, const void* userData, void* fnDestroyObj)
77 : {
78 : (void)userData;
79 15 : mmSetData64(&obj->refCount, 0);
80 15 : if (fnDestroyObj != NULL) {
81 12 : ((FnDestroyRefObjValue)fnDestroyObj)(obj);
82 : }
83 15 : }
84 :
85 0 : void* GetObjRef(RefObj* obj, FnCreateRefObjValue fnCreateObj)
86 : {
87 0 : RefObjUpdate update = {1, 0};
88 0 : if (!ObjRefCount(obj, &update, CreateRefObjVal, fnCreateObj, NULL)) {
89 0 : return NULL;
90 : }
91 0 : if (obj->obj == NULL) {
92 0 : ReleaseObjRef(obj, NULL);
93 : }
94 0 : return obj->obj;
95 : }
96 :
97 16 : void* GetObjRefWithUserData(RefObj* obj, const void* userData, FnCreateRefObjValueWithUserData fnCreateObj)
98 : {
99 16 : RefObjUpdate update = {1, 0};
100 16 : if (!ObjRefCount(obj, &update, CreateRefObjValWithUserData, fnCreateObj, userData)) {
101 0 : return NULL;
102 : }
103 16 : if (obj->obj == NULL) {
104 3 : ReleaseObjRef(obj, NULL);
105 : }
106 16 : return obj->obj;
107 : }
108 :
109 16 : void ReleaseObjRef(RefObj* obj, FnDestroyRefObjValue fnDestroyObj)
110 : {
111 16 : RefObjUpdate update = {-1, 1};
112 16 : (void)ObjRefCount(obj, &update, DestroyRefObjVal, fnDestroyObj, NULL);
113 16 : }
114 :
115 : #ifdef __cplusplus
116 : }
117 : #endif
|