sde: Implement sequence locker to lock across multiple APIs.
1. Lock prepare() and set() APIs using sequence entry and sequence exit lock respectively to prevent the critical section being accessed by other threads. 2. Wait for sequence wait lock on HotPlugEvent thread or any other binder threads(Eg. dumpsys), before it accesses the critical region. 3. Prevent deadlock during multiple prepare() calls before a set(). Change-Id: I5443675c870ed2967615ec383dd2d59ded30b52b
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2014 - 2015, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
* provided that the following conditions are met:
|
* provided that the following conditions are met:
|
||||||
@@ -28,7 +28,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#define SCOPE_LOCK(locker) Locker::ScopeLock scopeLock(locker)
|
#define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker)
|
||||||
|
#define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker)
|
||||||
|
#define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker)
|
||||||
|
#define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker)
|
||||||
|
#define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker)
|
||||||
|
|
||||||
namespace sde {
|
namespace sde {
|
||||||
|
|
||||||
@@ -48,7 +52,78 @@ class Locker {
|
|||||||
Locker &locker_;
|
Locker &locker_;
|
||||||
};
|
};
|
||||||
|
|
||||||
Locker() {
|
class SequenceEntryScopeLock {
|
||||||
|
public:
|
||||||
|
explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) {
|
||||||
|
locker_.Lock();
|
||||||
|
locker_.sequence_wait_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SequenceEntryScopeLock() {
|
||||||
|
locker_.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Locker &locker_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SequenceExitScopeLock {
|
||||||
|
public:
|
||||||
|
explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) {
|
||||||
|
locker_.Lock();
|
||||||
|
locker_.sequence_wait_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SequenceExitScopeLock() {
|
||||||
|
locker_.Broadcast();
|
||||||
|
locker_.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Locker &locker_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SequenceWaitScopeLock {
|
||||||
|
public:
|
||||||
|
explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) {
|
||||||
|
locker_.Lock();
|
||||||
|
|
||||||
|
if (locker_.sequence_wait_ == 1) {
|
||||||
|
locker_.Wait();
|
||||||
|
error_ = (locker_.sequence_wait_ == -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~SequenceWaitScopeLock() {
|
||||||
|
locker_.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsError() {
|
||||||
|
return error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Locker &locker_;
|
||||||
|
bool error_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SequenceCancelScopeLock {
|
||||||
|
public:
|
||||||
|
explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) {
|
||||||
|
locker_.Lock();
|
||||||
|
locker_.sequence_wait_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SequenceCancelScopeLock() {
|
||||||
|
locker_.Broadcast();
|
||||||
|
locker_.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Locker &locker_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Locker() : sequence_wait_(0) {
|
||||||
pthread_mutex_init(&mutex_, 0);
|
pthread_mutex_init(&mutex_, 0);
|
||||||
pthread_cond_init(&condition_, 0);
|
pthread_cond_init(&condition_, 0);
|
||||||
}
|
}
|
||||||
@@ -63,7 +138,7 @@ class Locker {
|
|||||||
void Signal() { pthread_cond_signal(&condition_); }
|
void Signal() { pthread_cond_signal(&condition_); }
|
||||||
void Broadcast() { pthread_cond_broadcast(&condition_); }
|
void Broadcast() { pthread_cond_broadcast(&condition_); }
|
||||||
void Wait() { pthread_cond_wait(&condition_, &mutex_); }
|
void Wait() { pthread_cond_wait(&condition_, &mutex_); }
|
||||||
int WaitFinite(long int ms) {
|
int WaitFinite(int ms) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
@@ -77,6 +152,11 @@ class Locker {
|
|||||||
private:
|
private:
|
||||||
pthread_mutex_t mutex_;
|
pthread_mutex_t mutex_;
|
||||||
pthread_cond_t condition_;
|
pthread_cond_t condition_;
|
||||||
|
int sequence_wait_; // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
|
||||||
|
// Some routines will wait for sequence of function calls to finish
|
||||||
|
// so that capturing a transitionary snapshot of context is prevented.
|
||||||
|
// If flag is set to -1, these routines will exit without doing any
|
||||||
|
// further processing.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sde
|
} // namespace sde
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ int HWCSession::Prepare(hwc_composer_device_1 *device, size_t num_displays,
|
|||||||
hwc_display_contents_1_t **displays) {
|
hwc_display_contents_1_t **displays) {
|
||||||
DTRACE_SCOPED();
|
DTRACE_SCOPED();
|
||||||
|
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device || !displays) {
|
if (!device || !displays) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -254,7 +254,7 @@ int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
|
|||||||
hwc_display_contents_1_t **displays) {
|
hwc_display_contents_1_t **displays) {
|
||||||
DTRACE_SCOPED();
|
DTRACE_SCOPED();
|
||||||
|
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_EXIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device || !displays) {
|
if (!device || !displays) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -289,7 +289,7 @@ int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
|
int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -317,7 +317,7 @@ int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
|
int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -348,6 +348,8 @@ int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
|
int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
|
||||||
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device || !value) {
|
if (!device || !value) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -365,7 +367,7 @@ void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
|
void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device || !buffer || !length) {
|
if (!device || !buffer || !length) {
|
||||||
return;
|
return;
|
||||||
@@ -376,6 +378,8 @@ void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
|
|||||||
|
|
||||||
int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
|
int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
|
||||||
size_t *num_configs) {
|
size_t *num_configs) {
|
||||||
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device || !configs || !num_configs) {
|
if (!device || !configs || !num_configs) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -406,6 +410,8 @@ int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint3
|
|||||||
|
|
||||||
int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
|
int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
|
||||||
const uint32_t *attributes, int32_t *values) {
|
const uint32_t *attributes, int32_t *values) {
|
||||||
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device || !attributes || !values) {
|
if (!device || !attributes || !values) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -435,6 +441,8 @@ int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
|
int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
|
||||||
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -464,6 +472,8 @@ int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
|
int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
|
||||||
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -549,6 +559,8 @@ DisplayError HWCSession::Hotplug(const CoreEventHotplug &hotplug) {
|
|||||||
|
|
||||||
android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
|
android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
|
||||||
android::Parcel */*output_parcel*/) {
|
android::Parcel */*output_parcel*/) {
|
||||||
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case qService::IQService::DYNAMIC_DEBUG:
|
case qService::IQService::DYNAMIC_DEBUG:
|
||||||
DynamicDebug(input_parcel);
|
DynamicDebug(input_parcel);
|
||||||
@@ -666,7 +678,7 @@ int HWCSession::HotPlugHandler(bool connected) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (connected) {
|
if (connected) {
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
if (display_external_) {
|
if (display_external_) {
|
||||||
DLOGE("HDMI already connected");
|
DLOGE("HDMI already connected");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -683,7 +695,7 @@ int HWCSession::HotPlugHandler(bool connected) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SCOPE_LOCK(locker_);
|
SEQUENCE_WAIT_SCOPE_LOCK(locker_);
|
||||||
if (!display_external_) {
|
if (!display_external_) {
|
||||||
DLOGE("HDMI not connected");
|
DLOGE("HDMI not connected");
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user