1cb69b360Sopenharmony_ci/*
2cb69b360Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3cb69b360Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cb69b360Sopenharmony_ci * you may not use this file except in compliance with the License.
5cb69b360Sopenharmony_ci * You may obtain a copy of the License at
6cb69b360Sopenharmony_ci *
7cb69b360Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cb69b360Sopenharmony_ci *
9cb69b360Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cb69b360Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cb69b360Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb69b360Sopenharmony_ci * See the License for the specific language governing permissions and
13cb69b360Sopenharmony_ci * limitations under the License.
14cb69b360Sopenharmony_ci */
15cb69b360Sopenharmony_ci
16cb69b360Sopenharmony_ci#include <stdio.h>
17cb69b360Sopenharmony_ci#include <stdint.h>
18cb69b360Sopenharmony_ci#include <unistd.h>
19cb69b360Sopenharmony_ci#include <pthread.h>
20cb69b360Sopenharmony_ci#include "hilog_wrapper.h"
21cb69b360Sopenharmony_ci#include "power/suspend_ops.h"
22cb69b360Sopenharmony_ci
23cb69b360Sopenharmony_ci#define SUSPEND_CHECK_INTERVAL_US       500000
24cb69b360Sopenharmony_ci
25cb69b360Sopenharmony_cistatic pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
26cb69b360Sopenharmony_cistatic pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER;
27cb69b360Sopenharmony_cistatic pthread_t g_suspendThread;
28cb69b360Sopenharmony_cistatic AutoSuspendLoop g_suspendLoop = NULL;
29cb69b360Sopenharmony_cistatic uint32_t g_suspendBlockCounter = 0;
30cb69b360Sopenharmony_ci
31cb69b360Sopenharmony_ciint usleep(useconds_t usec);
32cb69b360Sopenharmony_cistatic BOOL SuspendConditionSatisfied()
33cb69b360Sopenharmony_ci{
34cb69b360Sopenharmony_ci    return (g_suspendBlockCounter == 0) ? TRUE : FALSE;
35cb69b360Sopenharmony_ci}
36cb69b360Sopenharmony_ci
37cb69b360Sopenharmony_cistatic void WaitingSuspendCondition()
38cb69b360Sopenharmony_ci{
39cb69b360Sopenharmony_ci    pthread_mutex_lock(&g_mutex);
40cb69b360Sopenharmony_ci    while (SuspendConditionSatisfied() == FALSE) {
41cb69b360Sopenharmony_ci        pthread_cond_wait(&g_cond, &g_mutex);
42cb69b360Sopenharmony_ci    }
43cb69b360Sopenharmony_ci    pthread_mutex_unlock(&g_mutex);
44cb69b360Sopenharmony_ci}
45cb69b360Sopenharmony_ci
46cb69b360Sopenharmony_cistatic void *SuspendThreadLoop(void *arg)
47cb69b360Sopenharmony_ci{
48cb69b360Sopenharmony_ci    if (!g_suspendLoop) {
49cb69b360Sopenharmony_ci        return NULL;
50cb69b360Sopenharmony_ci    }
51cb69b360Sopenharmony_ci
52cb69b360Sopenharmony_ci    POWER_HILOGI("Suspend thread enter loop");
53cb69b360Sopenharmony_ci    while (1) {
54cb69b360Sopenharmony_ci        usleep(SUSPEND_CHECK_INTERVAL_US);
55cb69b360Sopenharmony_ci        if (g_suspendLoop(WaitingSuspendCondition) == FALSE) {
56cb69b360Sopenharmony_ci            break;
57cb69b360Sopenharmony_ci        }
58cb69b360Sopenharmony_ci    }
59cb69b360Sopenharmony_ci    return NULL;
60cb69b360Sopenharmony_ci}
61cb69b360Sopenharmony_ci
62cb69b360Sopenharmony_cistatic void Enable()
63cb69b360Sopenharmony_ci{
64cb69b360Sopenharmony_ci    static BOOL started = FALSE;
65cb69b360Sopenharmony_ci    if (started == TRUE) {
66cb69b360Sopenharmony_ci        return;
67cb69b360Sopenharmony_ci    }
68cb69b360Sopenharmony_ci
69cb69b360Sopenharmony_ci    int32_t ret = pthread_create(&g_suspendThread, NULL, SuspendThreadLoop, NULL);
70cb69b360Sopenharmony_ci    if (ret != 0) {
71cb69b360Sopenharmony_ci        POWER_HILOGE("Failed to create suspend thread");
72cb69b360Sopenharmony_ci        return;
73cb69b360Sopenharmony_ci    }
74cb69b360Sopenharmony_ci    pthread_detach(g_suspendThread);
75cb69b360Sopenharmony_ci    started = TRUE;
76cb69b360Sopenharmony_ci}
77cb69b360Sopenharmony_ci
78cb69b360Sopenharmony_cistatic void IncSuspendBlockCounter()
79cb69b360Sopenharmony_ci{
80cb69b360Sopenharmony_ci    pthread_mutex_lock(&g_mutex);
81cb69b360Sopenharmony_ci    g_suspendBlockCounter++;
82cb69b360Sopenharmony_ci    POWER_HILOGD("Suspend block counter: %{public}d", g_suspendBlockCounter);
83cb69b360Sopenharmony_ci    pthread_mutex_unlock(&g_mutex);
84cb69b360Sopenharmony_ci}
85cb69b360Sopenharmony_ci
86cb69b360Sopenharmony_cistatic void DecSuspendBlockCounter()
87cb69b360Sopenharmony_ci{
88cb69b360Sopenharmony_ci    pthread_mutex_lock(&g_mutex);
89cb69b360Sopenharmony_ci    g_suspendBlockCounter--;
90cb69b360Sopenharmony_ci    POWER_HILOGD("Suspend block counter: %{public}d", g_suspendBlockCounter);
91cb69b360Sopenharmony_ci    if (SuspendConditionSatisfied() == TRUE) {
92cb69b360Sopenharmony_ci        pthread_cond_signal(&g_cond);
93cb69b360Sopenharmony_ci    }
94cb69b360Sopenharmony_ci    pthread_mutex_unlock(&g_mutex);
95cb69b360Sopenharmony_ci}
96cb69b360Sopenharmony_ci
97cb69b360Sopenharmony_cistatic struct AutoSuspendOps g_ops = {
98cb69b360Sopenharmony_ci    .Enable = Enable,
99cb69b360Sopenharmony_ci    .IncSuspendBlockCounter = IncSuspendBlockCounter,
100cb69b360Sopenharmony_ci    .DecSuspendBlockCounter = DecSuspendBlockCounter,
101cb69b360Sopenharmony_ci};
102cb69b360Sopenharmony_ci
103cb69b360Sopenharmony_cistruct AutoSuspendOps* AutoSuspendOpsInit()
104cb69b360Sopenharmony_ci{
105cb69b360Sopenharmony_ci    g_suspendLoop = AutoSuspendLoopInit();
106cb69b360Sopenharmony_ci    if (!g_suspendLoop) {
107cb69b360Sopenharmony_ci        POWER_HILOGE("Failed to init auto suspend loop");
108cb69b360Sopenharmony_ci        return NULL;
109cb69b360Sopenharmony_ci    }
110cb69b360Sopenharmony_ci    return &g_ops;
111cb69b360Sopenharmony_ci}
112