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