2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler <axeld@pinc-software.de>
7 * Oliver Tappe <zooey@hirschkaefer.de>
18 #include <JobPrivate.h>
21 namespace BSupportKit
{
26 struct JobQueue::JobPriorityLess
{
27 bool operator()(const BJob
* left
, const BJob
* right
) const;
32 1. descending count of dependencies (only jobs without dependencies are
34 2. job ticket number (order in which jobs were added to the queue)
37 JobQueue::JobPriorityLess::operator()(const BJob
* left
, const BJob
* right
) const
39 int32 difference
= left
->CountDependencies() - right
->CountDependencies();
45 return left
->TicketNumber() < right
->TicketNumber();
49 class JobQueue::JobPriorityQueue
50 : public std::set
<BJob
*, JobPriorityLess
> {
62 fInitStatus
= _Init();
74 JobQueue::InitCheck() const
81 JobQueue::AddJob(BJob
* job
)
83 if (fQueuedJobs
== NULL
)
86 BAutolock
lock(&fLock
);
91 if (!fQueuedJobs
->insert(job
).second
)
93 } catch (const std::bad_alloc
& e
) {
98 BJob::Private(*job
).SetTicketNumber(fNextTicketNumber
++);
99 job
->AddStateListener(this);
100 if (job
->IsRunnable())
101 release_sem(fHaveRunnableJobSem
);
108 JobQueue::RemoveJob(BJob
* job
)
110 if (fQueuedJobs
== NULL
)
113 BAutolock
lock(&fLock
);
114 if (lock
.IsLocked()) {
116 if (fQueuedJobs
->erase(job
) == 0)
117 return B_NAME_NOT_FOUND
;
121 BJob::Private(*job
).ClearTicketNumber();
122 job
->RemoveStateListener(this);
130 JobQueue::JobSucceeded(BJob
* job
)
132 BAutolock
lock(&fLock
);
134 _RequeueDependantJobsOf(job
);
139 JobQueue::JobFailed(BJob
* job
)
141 BAutolock
lock(&fLock
);
143 _RemoveDependantJobsOf(job
);
151 if (Pop(B_INFINITE_TIMEOUT
, true, &job
) == B_OK
)
159 JobQueue::Pop(bigtime_t timeout
, bool returnWhenEmpty
, BJob
** _job
)
161 BAutolock
lock(&fLock
);
162 if (lock
.IsLocked()) {
164 JobPriorityQueue::iterator head
= fQueuedJobs
->begin();
165 if (head
!= fQueuedJobs
->end()) {
166 if ((*head
)->IsRunnable()) {
168 fQueuedJobs
->erase(head
);
171 } else if (returnWhenEmpty
)
172 return B_ENTRY_NOT_FOUND
;
174 // we need to wait until a job becomes available/runnable
178 result
= acquire_sem_etc(fHaveRunnableJobSem
, 1,
179 B_RELATIVE_TIMEOUT
, timeout
);
182 } while (result
== B_INTERRUPTED
);
193 JobQueue::CountJobs() const
195 BAutolock
locker(fLock
);
196 return fQueuedJobs
->size();
203 if (fHaveRunnableJobSem
< 0)
206 BAutolock
lock(&fLock
);
207 if (lock
.IsLocked()) {
208 delete_sem(fHaveRunnableJobSem
);
209 fHaveRunnableJobSem
= -1;
211 if (fQueuedJobs
!= NULL
) {
212 // get rid of all jobs
213 for (JobPriorityQueue::iterator iter
= fQueuedJobs
->begin();
214 iter
!= fQueuedJobs
->end(); ++iter
) {
217 fQueuedJobs
->clear();
226 status_t result
= fLock
.InitCheck();
230 fQueuedJobs
= new (std::nothrow
) JobPriorityQueue();
231 if (fQueuedJobs
== NULL
)
234 fHaveRunnableJobSem
= create_sem(0, "have runnable job");
235 if (fHaveRunnableJobSem
< 0)
236 return fHaveRunnableJobSem
;
243 JobQueue::_RequeueDependantJobsOf(BJob
* job
)
245 while (BJob
* dependantJob
= job
->DependantJobAt(0)) {
246 JobPriorityQueue::iterator found
= fQueuedJobs
->find(dependantJob
);
247 bool removed
= false;
248 if (found
!= fQueuedJobs
->end()) {
250 fQueuedJobs
->erase(dependantJob
);
255 dependantJob
->RemoveDependency(job
);
257 // Only insert a job if it was in our queue before
259 fQueuedJobs
->insert(dependantJob
);
260 if (dependantJob
->IsRunnable())
261 release_sem(fHaveRunnableJobSem
);
270 JobQueue::_RemoveDependantJobsOf(BJob
* job
)
272 while (BJob
* dependantJob
= job
->DependantJobAt(0)) {
274 fQueuedJobs
->erase(dependantJob
);
278 if (dependantJob
->State() != B_JOB_STATE_ABORTED
) {
279 BJob::Private(*dependantJob
).SetState(B_JOB_STATE_ABORTED
);
280 BJob::Private(*dependantJob
).NotifyStateListeners();
283 _RemoveDependantJobsOf(dependantJob
);
284 dependantJob
->RemoveDependency(job
);
285 // TODO: we need some sort of ownership management
291 } // namespace BPrivate
293 } // namespace BPackageKit