Shaka Packager SDK
Loading...
Searching...
No Matches
job_manager.cc
1// Copyright 2017 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/app/job_manager.h>
8
9#include <functional>
10#include <memory>
11#include <set>
12#include <string>
13#include <thread>
14#include <utility>
15
16#include <absl/log/check.h>
17#include <absl/synchronization/mutex.h>
18
19#include <packager/media/chunking/sync_point_queue.h>
20#include <packager/media/origin/origin_handler.h>
21#include <packager/status.h>
22
23namespace shaka {
24namespace media {
25
26Job::Job(const std::string& name,
27 std::shared_ptr<OriginHandler> work,
28 OnCompleteFunction on_complete)
29 : name_(name),
30 work_(std::move(work)),
31 on_complete_(on_complete),
32 status_(error::Code::UNKNOWN, "Job uninitialized") {
33 DCHECK(work_);
34}
35
36const Status& Job::Initialize() {
37 status_ = work_->Initialize();
38 return status_;
39}
40
41void Job::Start() {
42 thread_.reset(new std::thread(&Job::Run, this));
43}
44
45void Job::Cancel() {
46 work_->Cancel();
47}
48
49const Status& Job::Run() {
50 if (status_.ok()) // initialized correctly
51 status_ = work_->Run();
52
53 on_complete_(this);
54
55 return status_;
56}
57
58void Job::Join() {
59 if (thread_) {
60 thread_->join();
61 thread_ = nullptr;
62 }
63}
64
65JobManager::JobManager(std::unique_ptr<SyncPointQueue> sync_points)
66 : sync_points_(std::move(sync_points)) {}
67
68void JobManager::Add(const std::string& name,
69 std::shared_ptr<OriginHandler> handler) {
70 jobs_.emplace_back(new Job(
71 name, std::move(handler),
72 std::bind(&JobManager::OnJobComplete, this, std::placeholders::_1)));
73}
74
75Status JobManager::InitializeJobs() {
76 Status status;
77 for (auto& job : jobs_)
78 status.Update(job->Initialize());
79 return status;
80}
81
82Status JobManager::RunJobs() {
83 std::set<Job*> active_jobs;
84
85 // Start every job and add it to the active jobs list so that we can wait
86 // on each one.
87 for (auto& job : jobs_) {
88 job->Start();
89
90 active_jobs.insert(job.get());
91 }
92
93 // Wait for all jobs to complete or any job to error.
94 Status status;
95 {
96 absl::MutexLock lock(mutex_);
97 while (status.ok() && active_jobs.size()) {
98 // any_job_complete_ is protected by mutex_.
99 any_job_complete_.Wait(&mutex_);
100
101 // complete_ is protected by mutex_.
102 for (const auto& entry : complete_) {
103 Job* job = entry.first;
104 bool complete = entry.second;
105 if (complete) {
106 job->Join();
107 status.Update(job->status());
108 active_jobs.erase(job);
109 }
110 }
111 }
112 }
113
114 // If the main loop has exited and there are still jobs running,
115 // we need to cancel them and clean-up.
116 if (sync_points_)
117 sync_points_->Cancel();
118
119 for (auto& job : active_jobs)
120 job->Cancel();
121
122 for (auto& job : active_jobs)
123 job->Join();
124
125 return status;
126}
127
128void JobManager::OnJobComplete(Job* job) {
129 absl::MutexLock lock(mutex_);
130 // These are both protected by mutex_.
131 complete_[job] = true;
132 any_job_complete_.Signal();
133}
134
135void JobManager::CancelJobs() {
136 if (sync_points_)
137 sync_points_->Cancel();
138
139 for (auto& job : jobs_)
140 job->Cancel();
141}
142
143} // namespace media
144} // namespace shaka
All the methods that are virtual are virtual for mocking.