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 | |
parent | c002794bc04a1e6b64070d33754a49022a30aadb (diff) |
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>
-rw-r--r-- | Android.mk | 3 | ||||
-rw-r--r-- | worker.cpp | 183 | ||||
-rw-r--r-- | worker.h | 72 |
3 files changed, 257 insertions, 1 deletions
@@ -44,7 +44,8 @@ LOCAL_SRC_FILES := \ drmmode.cpp \ drmplane.cpp \ drmproperty.cpp \ - hwcomposer.cpp + hwcomposer.cpp \ + worker.cpp ifeq ($(strip $(BUFFER_IMPORTER)),drm-gralloc) LOCAL_C_INCLUDES += external/drm_gralloc 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; +} +} diff --git a/worker.h b/worker.h new file mode 100644 index 0000000..492693c --- /dev/null +++ b/worker.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef ANDROID_WORKER_H_ +#define ANDROID_WORKER_H_ + +#include <pthread.h> +#include <string> + +namespace android { + +class Worker { + public: + int Lock(); + int Unlock(); + + // Must be called with the lock acquired + int SignalLocked(); + int ExitLocked(); + + // Convenience versions of above, acquires the lock + int Signal(); + int Exit(); + + protected: + Worker(const char *name, int priority); + virtual ~Worker(); + + int InitWorker(); + + bool initialized() const; + + virtual void Routine() = 0; + + /* + * Must be called with the lock acquired. + * Returns -EINTR if interrupted by exit request + */ + int WaitForSignalOrExitLocked(); + + private: + static void *InternalRoutine(void *worker); + + // Must be called with the lock acquired + int SignalThreadLocked(bool exit); + + std::string name_; + int priority_; + + pthread_t thread_; + pthread_mutex_t lock_; + pthread_cond_t cond_; + + bool exit_; + bool initialized_; +}; +} + +#endif |