1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chpp/platform/platform_notifier.h"
18 
19 #include <pthread.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #include "chpp/macros.h"
24 #include "chpp/mutex.h"
25 #include "chpp/platform/platform_time.h"
26 #include "chpp/transport.h"
27 #include "chpp/transport_signals.h"
28 #include "time.h"
29 
30 /************************************************
31  *  Public Functions
32  ***********************************************/
33 
34 void chppPlatformNotifierInit(struct ChppNotifier *notifier) {
35   chppMutexInit(&notifier->mutex);
36   pthread_cond_init(&notifier->cond, NULL);
37 }
38 
39 void chppPlatformNotifierDeinit(struct ChppNotifier *notifier) {
40   pthread_cond_destroy(&notifier->cond);
41   chppMutexDeinit(&notifier->mutex);
42 }
43 
44 uint32_t chppPlatformNotifierGetSignal(struct ChppNotifier *notifier) {
45   chppMutexLock(&notifier->mutex);
46 
47   uint32_t signal = notifier->signal;
48   notifier->signal = 0;
49 
50   chppMutexUnlock(&notifier->mutex);
51   return signal;
52 }
53 
54 uint32_t chppPlatformNotifierWait(struct ChppNotifier *notifier) {
55   chppMutexLock(&notifier->mutex);
56 
57   while (notifier->signal == 0) {
58     pthread_cond_wait(&notifier->cond, &notifier->mutex.lock);
59   }
60   uint32_t signal = notifier->signal;
61   notifier->signal = 0;
62 
63   chppMutexUnlock(&notifier->mutex);
64   return signal;
65 }
66 uint32_t chppPlatformNotifierTimedWait(struct ChppNotifier *notifier,
67                                        uint64_t timeoutNs) {
68   if (timeoutNs == CHPP_TRANSPORT_TIMEOUT_INFINITE) {
69     return chppPlatformNotifierWait(notifier);
70 
71   } else {
72     struct timespec timeout;
73     struct timespec absTime;
74     uint64_t timeoutS = timeoutNs / CHPP_NSEC_PER_SEC;
75     timeoutNs = timeoutNs % CHPP_NSEC_PER_SEC;
76 
77     chppMutexLock(&notifier->mutex);
78 
79     clock_gettime(CLOCK_REALTIME, &absTime);
80     timeout = absTime;
81     timeout.tv_sec += timeoutS;
82     timeout.tv_nsec += timeoutNs;
83 
84     while ((notifier->signal == 0) &&
85            (CHPP_TIMESPEC_TO_NS(absTime) < CHPP_TIMESPEC_TO_NS(timeout))) {
86       pthread_cond_timedwait(&notifier->cond, &notifier->mutex.lock, &absTime);
87       clock_gettime(CLOCK_REALTIME, &absTime);
88     }
89     uint32_t signal = notifier->signal;
90     notifier->signal = 0;
91 
92     chppMutexUnlock(&notifier->mutex);
93     return signal;
94   }
95 }
96 
97 void chppPlatformNotifierSignal(struct ChppNotifier *notifier,
98                                 uint32_t signal) {
99   chppMutexLock(&notifier->mutex);
100 
101   notifier->signal |= signal;
102   pthread_cond_signal(&notifier->cond);
103 
104   chppMutexUnlock(&notifier->mutex);
105 }
106