1 /* 2 * Copyright (C) 2015 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 #define LOG_TAG "hwc-drm-worker" 18 19 #include "worker.h" 20 21 #include <errno.h> 22 #include <pthread.h> 23 #include <stdlib.h> 24 #include <sys/resource.h> 25 #include <sys/signal.h> 26 #include <time.h> 27 28 #include <cutils/log.h> 29 30 namespace android { 31 32 static const int64_t kBillion = 1000000000LL; 33 34 Worker::Worker(const char *name, int priority) 35 : name_(name), priority_(priority), exit_(false), initialized_(false) { 36 } 37 38 Worker::~Worker() { 39 if (!initialized_) 40 return; 41 42 pthread_kill(thread_, SIGTERM); 43 pthread_cond_destroy(&cond_); 44 pthread_mutex_destroy(&lock_); 45 } 46 47 int Worker::InitWorker() { 48 pthread_condattr_t cond_attr; 49 pthread_condattr_init(&cond_attr); 50 pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC); 51 int ret = pthread_cond_init(&cond_, &cond_attr); 52 if (ret) { 53 ALOGE("Failed to int thread %s condition %d", name_.c_str(), ret); 54 return ret; 55 } 56 57 ret = pthread_mutex_init(&lock_, NULL); 58 if (ret) { 59 ALOGE("Failed to init thread %s lock %d", name_.c_str(), ret); 60 pthread_cond_destroy(&cond_); 61 return ret; 62 } 63 64 ret = pthread_create(&thread_, NULL, InternalRoutine, this); 65 if (ret) { 66 ALOGE("Could not create thread %s %d", name_.c_str(), ret); 67 pthread_mutex_destroy(&lock_); 68 pthread_cond_destroy(&cond_); 69 return ret; 70 } 71 initialized_ = true; 72 return 0; 73 } 74 75 bool Worker::initialized() const { 76 return initialized_; 77 } 78 79 int Worker::Lock() { 80 return pthread_mutex_lock(&lock_); 81 } 82 83 int Worker::Unlock() { 84 return pthread_mutex_unlock(&lock_); 85 } 86 87 int Worker::SignalLocked() { 88 return SignalThreadLocked(false); 89 } 90 91 int Worker::ExitLocked() { 92 int signal_ret = SignalThreadLocked(true); 93 if (signal_ret) 94 ALOGE("Failed to signal thread %s with exit %d", name_.c_str(), signal_ret); 95 96 int join_ret = pthread_join(thread_, NULL); 97 if (join_ret && join_ret != ESRCH) 98 ALOGE("Failed to join thread %s in exit %d", name_.c_str(), join_ret); 99 100 return signal_ret | join_ret; 101 } 102 103 int Worker::Signal() { 104 int ret = Lock(); 105 if (ret) { 106 ALOGE("Failed to acquire lock in Signal() %d\n", ret); 107 return ret; 108 } 109 110 int signal_ret = SignalLocked(); 111 112 ret = Unlock(); 113 if (ret) { 114 ALOGE("Failed to release lock in Signal() %d\n", ret); 115 return ret; 116 } 117 return signal_ret; 118 } 119 120 int Worker::Exit() { 121 int ret = Lock(); 122 if (ret) { 123 ALOGE("Failed to acquire lock in Exit() %d\n", ret); 124 return ret; 125 } 126 127 int exit_ret = ExitLocked(); 128 129 ret = Unlock(); 130 if (ret) { 131 ALOGE("Failed to release lock in Exit() %d\n", ret); 132 return ret; 133 } 134 return exit_ret; 135 } 136 137 int Worker::WaitForSignalOrExitLocked(int64_t max_nanoseconds) { 138 if (exit_) 139 return -EINTR; 140 141 int ret = 0; 142 if (max_nanoseconds < 0) { 143 ret = pthread_cond_wait(&cond_, &lock_); 144 } else { 145 struct timespec abs_deadline; 146 ret = clock_gettime(CLOCK_MONOTONIC, &abs_deadline); 147 if (ret) 148 return ret; 149 int64_t nanos = (int64_t)abs_deadline.tv_nsec + max_nanoseconds; 150 abs_deadline.tv_sec += nanos / kBillion; 151 abs_deadline.tv_nsec = nanos % kBillion; 152 ret = pthread_cond_timedwait(&cond_, &lock_, &abs_deadline); 153 if (ret == ETIMEDOUT) 154 ret = -ETIMEDOUT; 155 } 156 157 if (exit_) 158 return -EINTR; 159 160 return ret; 161 } 162 163 // static 164 void *Worker::InternalRoutine(void *arg) { 165 Worker *worker = (Worker *)arg; 166 167 setpriority(PRIO_PROCESS, 0, worker->priority_); 168 169 while (true) { 170 int ret = worker->Lock(); 171 if (ret) { 172 ALOGE("Failed to lock %s thread %d", worker->name_.c_str(), ret); 173 continue; 174 } 175 176 bool exit = worker->exit_; 177 178 ret = worker->Unlock(); 179 if (ret) { 180 ALOGE("Failed to unlock %s thread %d", worker->name_.c_str(), ret); 181 break; 182 } 183 if (exit) 184 break; 185 186 worker->Routine(); 187 } 188 return NULL; 189 } 190 191 int Worker::SignalThreadLocked(bool exit) { 192 if (exit) 193 exit_ = exit; 194 195 int ret = pthread_cond_signal(&cond_); 196 if (ret) { 197 ALOGE("Failed to signal condition on %s thread %d", name_.c_str(), ret); 198 return ret; 199 } 200 201 return 0; 202 } 203 } 204