diff options
author | Sean Paul <seanpaul@chromium.org> | 2015-05-13 06:22:10 -0700 |
---|---|---|
committer | Sean Paul <seanpaul@chromium.org> | 2015-05-13 06:57:46 -0700 |
commit | cb8676c6dffe8ef0577ec4c367ad810a291ed390 (patch) | |
tree | 0385796b46013fd51962909b20f228fe01a3eee3 /worker.cpp | |
parent | c002794bc04a1e6b64070d33754a49022a30aadb (diff) | |
download | drm_hwcomposer-cb8676c6dffe8ef0577ec4c367ad810a291ed390.tar.gz |
drm_hwcomposer: Add Worker class to abstract thread nasties
This will allow us to spin up threads more easily.
Change-Id: I74add3d20ab14a61f3c646877a3ee17d0bd99ac4
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Diffstat (limited to 'worker.cpp')
-rw-r--r-- | worker.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/worker.cpp b/worker.cpp new file mode 100644 index 0000000..e169911 --- /dev/null +++ b/worker.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hwc-drm-worker" + +#include "worker.h" + +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <sys/resource.h> +#include <sys/signal.h> + +#include <cutils/log.h> + +namespace android { + +Worker::Worker(const char *name, int priority) + : name_(name), priority_(priority), exit_(false), initialized_(false) { +} + +Worker::~Worker() { + if (!initialized_) + return; + + pthread_kill(thread_, SIGTERM); + pthread_cond_destroy(&cond_); + pthread_mutex_destroy(&lock_); +} + +int Worker::InitWorker() { + int ret = pthread_cond_init(&cond_, NULL); + if (ret) { + ALOGE("Failed to int thread %s condition %d", name_.c_str(), ret); + return ret; + } + + ret = pthread_mutex_init(&lock_, NULL); + if (ret) { + ALOGE("Failed to init thread %s lock %d", name_.c_str(), ret); + pthread_cond_destroy(&cond_); + return ret; + } + + ret = pthread_create(&thread_, NULL, InternalRoutine, this); + if (ret) { + ALOGE("Could not create thread %s %d", name_.c_str(), ret); + pthread_mutex_destroy(&lock_); + pthread_cond_destroy(&cond_); + return ret; + } + initialized_ = true; + return 0; +} + +bool Worker::initialized() const { + return initialized_; +} + +int Worker::Lock() { + return pthread_mutex_lock(&lock_); +} + +int Worker::Unlock() { + return pthread_mutex_unlock(&lock_); +} + +int Worker::SignalLocked() { + return SignalThreadLocked(false); +} + +int Worker::ExitLocked() { + int signal_ret = SignalThreadLocked(true); + if (signal_ret) + ALOGE("Failed to signal thread %s with exit %d", name_.c_str(), signal_ret); + + int join_ret = pthread_join(thread_, NULL); + if (join_ret && join_ret != ESRCH) + ALOGE("Failed to join thread %s in exit %d", name_.c_str(), join_ret); + + return signal_ret | join_ret; +} + +int Worker::Signal() { + int ret = Lock(); + if (ret) { + ALOGE("Failed to acquire lock in Signal() %d\n", ret); + return ret; + } + + int signal_ret = SignalLocked(); + + ret = Unlock(); + if (ret) { + ALOGE("Failed to release lock in Signal() %d\n", ret); + return ret; + } + return signal_ret; +} + +int Worker::Exit() { + int ret = Lock(); + if (ret) { + ALOGE("Failed to acquire lock in Exit() %d\n", ret); + return ret; + } + + int exit_ret = ExitLocked(); + + ret = Unlock(); + if (ret) { + ALOGE("Failed to release lock in Exit() %d\n", ret); + return ret; + } + return exit_ret; +} + +int Worker::WaitForSignalOrExitLocked() { + if (exit_) + return -EINTR; + + int ret = pthread_cond_wait(&cond_, &lock_); + + if (exit_) + return -EINTR; + + return ret; +} + +// static +void *Worker::InternalRoutine(void *arg) { + Worker *worker = (Worker *)arg; + + setpriority(PRIO_PROCESS, 0, worker->priority_); + + while (true) { + int ret = worker->Lock(); + if (ret) { + ALOGE("Failed to lock %s thread %d", worker->name_.c_str(), ret); + continue; + } + + bool exit = worker->exit_; + + ret = worker->Unlock(); + if (ret) { + ALOGE("Failed to unlock %s thread %d", worker->name_.c_str(), ret); + break; + } + if (exit) + break; + + worker->Routine(); + } + return NULL; +} + +int Worker::SignalThreadLocked(bool exit) { + if (exit) + exit_ = exit; + + int ret = pthread_cond_signal(&cond_); + if (ret) { + ALOGE("Failed to signal condition on %s thread %d", name_.c_str(), ret); + return ret; + } + + return 0; +} +} |