Allow SyncPointQueue to be cancelled

Change-Id: Idbf6ee7a5d9721681811189fca4190e7a0286c83
This commit is contained in:
KongQun Yang 2018-03-21 23:24:17 -07:00
parent db45e0868a
commit 14aab56474
6 changed files with 47 additions and 11 deletions

View File

@ -7,6 +7,7 @@
#include "packager/app/job_manager.h"
#include "packager/app/libcrypto_threading.h"
#include "packager/media/chunking/sync_point_queue.h"
#include "packager/media/origin/origin_handler.h"
namespace shaka {
@ -29,6 +30,9 @@ void Job::Run() {
wait_.Signal();
}
JobManager::JobManager(std::unique_ptr<SyncPointQueue> sync_points)
: sync_points_(std::move(sync_points)) {}
void JobManager::Add(const std::string& name,
std::shared_ptr<OriginHandler> handler) {
// Stores Job entries for delayed construction of Job objects, to avoid
@ -87,6 +91,8 @@ Status JobManager::RunJobs() {
// If the main loop has exited and there are still jobs running,
// we need to cancel them and clean-up.
if (sync_points_)
sync_points_->Cancel();
for (auto& job : active_jobs) {
job->Cancel();
}
@ -99,6 +105,8 @@ Status JobManager::RunJobs() {
}
void JobManager::CancelJobs() {
if (sync_points_)
sync_points_->Cancel();
for (auto& job : jobs_) {
job->Cancel();
}

View File

@ -17,6 +17,7 @@ namespace shaka {
namespace media {
class OriginHandler;
class SyncPointQueue;
// A job is a single line of work that is expected to run in parallel with
// other jobs.
@ -54,7 +55,10 @@ class Job : public base::SimpleThread {
// jobs.
class JobManager {
public:
JobManager() = default;
// @param sync_points is an optional SyncPointQueue used to synchronize and
// align cue points. JobManager cancels @a sync_points when any job
// fails or is cancelled. It can be NULL.
explicit JobManager(std::unique_ptr<SyncPointQueue> sync_points);
// Create a new job entry by specifying the origin handler at the top of the
// chain and a name for the thread. This will only register the job. To start
@ -75,6 +79,8 @@ class JobManager {
// unblock a call to |RunJobs|.
void CancelJobs();
SyncPointQueue* sync_points() { return sync_points_.get(); }
private:
JobManager(const JobManager&) = delete;
JobManager& operator=(const JobManager&) = delete;
@ -86,6 +92,9 @@ class JobManager {
// Stores Job entries for delayed construction of Job object.
std::vector<JobEntry> job_entries_;
std::vector<std::unique_ptr<Job>> jobs_;
// Stored in JobManager so JobManager can cancel |sync_points| when any job
// fails or is cancelled.
std::unique_ptr<SyncPointQueue> sync_points_;
};
} // namespace media

View File

@ -170,7 +170,10 @@ Status CueAlignmentHandler::OnSample(std::unique_ptr<StreamData> sample) {
std::shared_ptr<const CueEvent> next_sync =
sync_points_->GetNext(next_cue_hint);
DCHECK(next_sync);
if (!next_sync) {
// This happens only if the job is cancelled.
return Status(error::CANCELLED, "SyncPointQueue is cancelled.");
}
Status status = UseNewSyncPoint(next_sync);
if (!status.ok()) {

View File

@ -27,6 +27,14 @@ void SyncPointQueue::AddThread() {
thread_count_++;
}
void SyncPointQueue::Cancel() {
{
base::AutoLock auto_lock(lock_);
cancelled_ = true;
}
sync_condition_.Broadcast();
}
double SyncPointQueue::GetHint(double time_in_seconds) {
base::AutoLock auto_lock(lock_);
@ -46,7 +54,7 @@ double SyncPointQueue::GetHint(double time_in_seconds) {
std::shared_ptr<const CueEvent> SyncPointQueue::GetNext(
double hint_in_seconds) {
base::AutoLock auto_lock(lock_);
while (true) {
while (!cancelled_) {
// Find the promoted cue that would line up with our hint, which is the
// first cue that is not less than |hint_in_seconds|.
auto iter = promoted_.lower_bound(hint_in_seconds);
@ -70,6 +78,7 @@ std::shared_ptr<const CueEvent> SyncPointQueue::GetNext(
sync_condition_.Wait();
waiting_thread_count_--;
}
return nullptr;
}
std::shared_ptr<const CueEvent> SyncPointQueue::PromoteAt(

View File

@ -26,6 +26,9 @@ class SyncPointQueue {
/// order to keep track of its clients.
void AddThread();
/// Cancel the queue and unblock all threads.
void Cancel();
/// @return A hint for when the next cue event would be. The returned hint is
/// not less than @a time_in_seconds. The actual time for the next cue
/// event will not be less than the returned hint, with the exact
@ -37,7 +40,7 @@ class SyncPointQueue {
/// after @a hint_in_seconds has been promoted, this will block until
/// either a cue is promoted or all threads are blocked (in which
/// case, the unpromoted cue at @a hint_in_seconds will be
/// self-promoted and returned).
/// self-promoted and returned) or Cancel() is called.
std::shared_ptr<const CueEvent> GetNext(double hint_in_seconds);
/// Promote the first cue that is not greater than @a time_in_seconds. All
@ -56,6 +59,7 @@ class SyncPointQueue {
base::ConditionVariable sync_condition_;
size_t thread_count_ = 0;
size_t waiting_thread_count_ = 0;
bool cancelled_ = false;
std::map<double, std::shared_ptr<CueEvent>> unpromoted_;
std::map<double, std::shared_ptr<CueEvent>> promoted_;

View File

@ -54,6 +54,7 @@ namespace shaka {
// TODO(kqyang): Clean up namespaces.
using media::Demuxer;
using media::JobManager;
using media::KeySource;
using media::MuxerOptions;
using media::SyncPointQueue;
@ -797,9 +798,8 @@ struct Packager::PackagerInternal {
std::unique_ptr<KeySource> encryption_key_source;
std::unique_ptr<MpdNotifier> mpd_notifier;
std::unique_ptr<hls::HlsNotifier> hls_notifier;
std::unique_ptr<SyncPointQueue> sync_points;
BufferCallbackParams buffer_callback_params;
media::JobManager job_manager;
std::unique_ptr<media::JobManager> job_manager;
};
Packager::Packager() {}
@ -869,10 +869,12 @@ Status Packager::Initialize(
internal->hls_notifier.reset(new hls::SimpleHlsNotifier(hls_params));
}
std::unique_ptr<SyncPointQueue> sync_points;
if (!packaging_params.ad_cue_generator_params.cue_points.empty()) {
internal->sync_points.reset(
sync_points.reset(
new SyncPointQueue(packaging_params.ad_cue_generator_params));
}
internal->job_manager.reset(new JobManager(std::move(sync_points)));
std::vector<StreamDescriptor> streams_for_jobs;
@ -916,8 +918,9 @@ Status Packager::Initialize(
Status status = media::CreateAllJobs(
streams_for_jobs, packaging_params, internal->mpd_notifier.get(),
internal->encryption_key_source.get(), internal->sync_points.get(),
&muxer_listener_factory, &muxer_factory, &internal->job_manager);
internal->encryption_key_source.get(),
internal->job_manager->sync_points(), &muxer_listener_factory,
&muxer_factory, internal->job_manager.get());
if (!status.ok()) {
return status;
@ -931,7 +934,7 @@ Status Packager::Run() {
if (!internal_)
return Status(error::INVALID_ARGUMENT, "Not yet initialized.");
Status status = internal_->job_manager.RunJobs();
Status status = internal_->job_manager->RunJobs();
if (!status.ok())
return status;
@ -951,7 +954,7 @@ void Packager::Cancel() {
LOG(INFO) << "Not yet initialized. Return directly.";
return;
}
internal_->job_manager.CancelJobs();
internal_->job_manager->CancelJobs();
}
std::string Packager::GetLibraryVersion() {