1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "running_lock.h"
17
18#include <stdint.h>
19#include <stdlib.h>
20
21#include <common.h>
22#include <ohos_errno.h>
23#include <pthread.h>
24#include <securec.h>
25
26#include "hilog_wrapper.h"
27#include "running_lock_entry.h"
28#include "running_lock_framework.h"
29
30static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
31static BOOL g_inited = FALSE;
32static Vector g_runningLocks;
33
34static BOOL AddRunningLock(RunningLock *lock)
35{
36    pthread_mutex_lock(&g_mutex);
37    if (g_inited == FALSE) {
38        g_runningLocks = VECTOR_Make(NULL, NULL);
39        g_inited = TRUE;
40    }
41    int16_t pos = VECTOR_Add(&g_runningLocks, (void *)lock);
42    if (pos == INVALID_INDEX) {
43        POWER_HILOGE("Failed to add lock to vector");
44        pthread_mutex_unlock(&g_mutex);
45        return FALSE;
46    }
47    POWER_HILOGD("Add running lock, name: %s, type: %d", lock->name, lock->type);
48    pthread_mutex_unlock(&g_mutex);
49    return TRUE;
50}
51
52static BOOL RemoveRunningLock(const RunningLock *lock)
53{
54    pthread_mutex_lock(&g_mutex);
55    int16_t pos = VECTOR_Find(&g_runningLocks, (void *)lock);
56    if (pos < 0) {
57        POWER_HILOGE("Non-existent running lock");
58        pthread_mutex_unlock(&g_mutex);
59        return FALSE;
60    }
61    VECTOR_Swap(&g_runningLocks, pos, NULL);
62    POWER_HILOGD("Remove running lock, name: %s, type: %d", lock->name, lock->type);
63    pthread_mutex_unlock(&g_mutex);
64    return TRUE;
65}
66
67static BOOL IsRunningLockExisted(const RunningLock *lock)
68{
69    if (lock == NULL) {
70        POWER_HILOGE("Invalid running lock");
71        return FALSE;
72    }
73    pthread_mutex_lock(&g_mutex);
74    BOOL ret = (VECTOR_Find(&g_runningLocks, (void *)lock) >= 0) ? TRUE : FALSE;
75    pthread_mutex_unlock(&g_mutex);
76    return ret;
77}
78
79static RunningLockEntry *CreateRunningLockEntry(const char *name, RunningLockType type, RunningLockFlag flag)
80{
81    RunningLockEntry *entry = (RunningLockEntry *)malloc(sizeof(RunningLockEntry));
82    if (entry == NULL) {
83        POWER_HILOGE("Failed allocate running lock entry");
84        return NULL;
85    }
86    (void)memset_s(entry, sizeof(RunningLockEntry), 0, sizeof(RunningLockEntry));
87    InitIdentity(entry);
88    entry->lock.type = type;
89    entry->lock.flag = flag;
90    if (strcpy_s(entry->lock.name, sizeof(entry->lock.name), name) != EOK) {
91        free(entry);
92        return NULL;
93    }
94    return entry;
95}
96
97static inline void DestroyRunningLockEntry(RunningLockEntry *entry)
98{
99    if (entry != NULL) {
100        POWER_HILOGD("Free entry: %p", entry);
101        free(entry);
102    }
103}
104
105const RunningLock *CreateRunningLock(const char *name, RunningLockType type, RunningLockFlag flag)
106{
107    if ((name == NULL) || (type >= RUNNINGLOCK_BUTT)) {
108        POWER_HILOGE("Invalid running lock name");
109        return NULL;
110    }
111
112    RunningLockEntry *entry = CreateRunningLockEntry(name, type, flag);
113    if (entry == NULL) {
114        POWER_HILOGE("Failed create running lock entry");
115        return NULL;
116    }
117    AddRunningLock(&entry->lock);
118    POWER_HILOGD("Create %s, pid: %u, token: %llu", name, entry->identity.pid, (long long)entry->identity.token);
119    return &entry->lock;
120}
121
122BOOL AcquireRunningLock(const RunningLock *lock)
123{
124    if (IsRunningLockExisted(lock) == FALSE) {
125        POWER_HILOGE("Non-existent running lock");
126        return FALSE;
127    }
128    RunningLockEntry *entry = GetRunningLockEntry(lock);
129    if (entry->status.isHolding == TRUE) {
130        POWER_HILOGD("Already acquired, name: %s", lock->name);
131        return TRUE;
132    }
133    entry->status.isHolding = AcquireRunningLockEntry(entry, -1);
134    return entry->status.isHolding;
135}
136
137BOOL ReleaseRunningLock(const RunningLock *lock)
138{
139    if (IsRunningLockExisted(lock) == FALSE) {
140        POWER_HILOGE("Non-existent running lock");
141        return FALSE;
142    }
143    RunningLockEntry *entry = GetRunningLockEntry(lock);
144    if (entry->status.isHolding == FALSE) {
145        POWER_HILOGD("Already released, name: %s", lock->name);
146        return TRUE;
147    }
148    entry->status.isHolding = !ReleaseRunningLockEntry(entry);
149    return !entry->status.isHolding;
150}
151
152void DestroyRunningLock(const RunningLock *lock)
153{
154    if (lock == NULL) {
155        POWER_HILOGE("Invalid running lock");
156        return;
157    }
158    ReleaseRunningLock(lock);
159    if (RemoveRunningLock(lock) == TRUE) {
160        DestroyRunningLockEntry(GetRunningLockEntry(lock));
161    }
162}
163
164BOOL IsRunningLockHolding(const RunningLock *lock)
165{
166    if (IsRunningLockExisted(lock) == FALSE) {
167        POWER_HILOGE("Non-existent running lock");
168        return FALSE;
169    }
170    RunningLockEntry *entry = GetRunningLockEntry(lock);
171    return entry->status.isHolding;
172}
173