Home | History | Annotate | Download | only in drm_hwcomposer
      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