Shaka Packager SDK
job_manager.cc
1 // Copyright 2017 Google Inc. 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 "packager/app/libcrypto_threading.h"
10 #include "packager/media/origin/origin_handler.h"
11 
12 namespace shaka {
13 namespace media {
14 
15 Job::Job(const std::string& name, std::shared_ptr<OriginHandler> work)
16  : SimpleThread(name),
17  work_(std::move(work)),
18  wait_(base::WaitableEvent::ResetPolicy::MANUAL,
19  base::WaitableEvent::InitialState::NOT_SIGNALED) {
20  DCHECK(work_);
21 }
22 
23 void Job::Cancel() {
24  work_->Cancel();
25 }
26 
27 void Job::Run() {
28  status_ = work_->Run();
29  wait_.Signal();
30 }
31 
32 void JobManager::Add(const std::string& name,
33  std::shared_ptr<OriginHandler> handler) {
34  // Stores Job entries for delayed construction of Job objects, to avoid
35  // setting up SimpleThread until we know all workers can be initialized
36  // successfully.
37  job_entries_.push_back({name, std::move(handler)});
38 }
39 
40 Status JobManager::InitializeJobs() {
41  Status status;
42  for (const JobEntry& job_entry : job_entries_)
43  status.Update(job_entry.worker->Initialize());
44  if (!status.ok())
45  return status;
46 
47  // Create Job objects after successfully initialized all workers.
48  for (const JobEntry& job_entry : job_entries_)
49  jobs_.emplace_back(new Job(job_entry.name, std::move(job_entry.worker)));
50  return status;
51 }
52 
53 Status JobManager::RunJobs() {
54  // We need to store the jobs and the waits separately in order to use the
55  // |WaitMany| function. |WaitMany| takes an array of WaitableEvents but we
56  // need to access the jobs in order to join the thread and check the status.
57  // The indexes needs to be check in sync or else we won't be able to relate a
58  // WaitableEvent back to the job.
59  std::vector<Job*> active_jobs;
60  std::vector<base::WaitableEvent*> active_waits;
61 
62  // Start every job and add it to the active jobs list so that we can wait
63  // on each one.
64  for (auto& job : jobs_) {
65  job->Start();
66 
67  active_jobs.push_back(job.get());
68  active_waits.push_back(job->wait());
69  }
70 
71  // Wait for all jobs to complete or an error occurs.
72  Status status;
73  while (status.ok() && active_jobs.size()) {
74  // Wait for an event to finish and then update our status so that we can
75  // quit if something has gone wrong.
76  const size_t done =
77  base::WaitableEvent::WaitMany(active_waits.data(), active_waits.size());
78  Job* job = active_jobs[done];
79 
80  job->Join();
81  status.Update(job->status());
82 
83  // Remove the job and the wait from our tracking.
84  active_jobs.erase(active_jobs.begin() + done);
85  active_waits.erase(active_waits.begin() + done);
86  }
87 
88  // If the main loop has exited and there are still jobs running,
89  // we need to cancel them and clean-up.
90  for (auto& job : active_jobs) {
91  job->Cancel();
92  }
93 
94  for (auto& job : active_jobs) {
95  job->Join();
96  }
97 
98  return status;
99 }
100 
101 void JobManager::CancelJobs() {
102  for (auto& job : jobs_) {
103  job->Cancel();
104  }
105 }
106 
107 } // namespace media
108 } // namespace shaka
STL namespace.
All the methods that are virtual are virtual for mocking.