JobQueue: fixed leak, notification, added Pop() variant.
* Was leaking fQueuedJobs on destruction. * fHaveRunnableJobSem implementation was not completed; it was never released. * Added Pop() variant that is a bit more flexible, and allows for a timeout as well as waiting even when the queue is empty, and can return a status code.
This commit is contained in:
parent
3375ee66bc
commit
6ff95509c2
@ -30,8 +30,12 @@ public:
|
|||||||
// gives up ownership
|
// gives up ownership
|
||||||
|
|
||||||
BJob* Pop();
|
BJob* Pop();
|
||||||
|
status_t Pop(bigtime_t timeout, bool returnWhenEmpty,
|
||||||
|
BJob** _job);
|
||||||
// caller owns job
|
// caller owns job
|
||||||
|
|
||||||
|
size_t CountJobs() const;
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -49,7 +53,7 @@ private:
|
|||||||
void _RequeueDependantJobsOf(BJob* job);
|
void _RequeueDependantJobsOf(BJob* job);
|
||||||
void _RemoveDependantJobsOf(BJob* job);
|
void _RemoveDependantJobsOf(BJob* job);
|
||||||
|
|
||||||
BLocker fLock;
|
mutable BLocker fLock;
|
||||||
uint32 fNextTicketNumber;
|
uint32 fNextTicketNumber;
|
||||||
JobPriorityQueue* fQueuedJobs;
|
JobPriorityQueue* fQueuedJobs;
|
||||||
sem_id fHaveRunnableJobSem;
|
sem_id fHaveRunnableJobSem;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
|
* Axel Dörfler <axeld@pinc-software.de>
|
||||||
* Oliver Tappe <zooey@hirschkaefer.de>
|
* Oliver Tappe <zooey@hirschkaefer.de>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -50,6 +51,9 @@ class JobQueue::JobPriorityQueue
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
JobQueue::JobQueue()
|
JobQueue::JobQueue()
|
||||||
:
|
:
|
||||||
fLock("job queue"),
|
fLock("job queue"),
|
||||||
@ -61,6 +65,8 @@ JobQueue::JobQueue()
|
|||||||
|
|
||||||
JobQueue::~JobQueue()
|
JobQueue::~JobQueue()
|
||||||
{
|
{
|
||||||
|
Close();
|
||||||
|
delete fQueuedJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,6 +95,8 @@ JobQueue::AddJob(BJob* job)
|
|||||||
}
|
}
|
||||||
BJob::Private(*job).SetTicketNumber(fNextTicketNumber++);
|
BJob::Private(*job).SetTicketNumber(fNextTicketNumber++);
|
||||||
job->AddStateListener(this);
|
job->AddStateListener(this);
|
||||||
|
if (job->IsRunnable())
|
||||||
|
release_sem(fHaveRunnableJobSem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@ -137,35 +145,54 @@ JobQueue::JobFailed(BJob* job)
|
|||||||
|
|
||||||
BJob*
|
BJob*
|
||||||
JobQueue::Pop()
|
JobQueue::Pop()
|
||||||
|
{
|
||||||
|
BJob* job;
|
||||||
|
if (Pop(B_INFINITE_TIMEOUT, true, &job) == B_OK)
|
||||||
|
return job;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
JobQueue::Pop(bigtime_t timeout, bool returnWhenEmpty, BJob** _job)
|
||||||
{
|
{
|
||||||
BAutolock lock(&fLock);
|
BAutolock lock(&fLock);
|
||||||
if (lock.IsLocked()) {
|
if (lock.IsLocked()) {
|
||||||
JobPriorityQueue::iterator head = fQueuedJobs->begin();
|
while (true) {
|
||||||
if (head == fQueuedJobs->end())
|
JobPriorityQueue::iterator head = fQueuedJobs->begin();
|
||||||
return NULL;
|
if (head != fQueuedJobs->end()) {
|
||||||
while (!(*head)->IsRunnable()) {
|
if ((*head)->IsRunnable()) {
|
||||||
// we need to wait until a job becomes runnable
|
*_job = *head;
|
||||||
|
fQueuedJobs->erase(head);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
} else if (returnWhenEmpty)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// we need to wait until a job becomes available/runnable
|
||||||
status_t result;
|
status_t result;
|
||||||
do {
|
do {
|
||||||
lock.Unlock();
|
lock.Unlock();
|
||||||
result = acquire_sem(fHaveRunnableJobSem);
|
result = acquire_sem_etc(fHaveRunnableJobSem, 1,
|
||||||
|
B_RELATIVE_TIMEOUT, timeout);
|
||||||
if (!lock.Lock())
|
if (!lock.Lock())
|
||||||
return NULL;
|
return B_ERROR;
|
||||||
} while (result == B_INTERRUPTED);
|
} while (result == B_INTERRUPTED);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return NULL;
|
return result;
|
||||||
|
|
||||||
// fetch current head, it must be runnable now
|
|
||||||
head = fQueuedJobs->begin();
|
|
||||||
if (head == fQueuedJobs->end())
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
BJob* job = *head;
|
|
||||||
fQueuedJobs->erase(head);
|
|
||||||
return job;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
JobQueue::CountJobs() const
|
||||||
|
{
|
||||||
|
BAutolock locker(fLock);
|
||||||
|
return fQueuedJobs->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -222,6 +249,8 @@ JobQueue::_RequeueDependantJobsOf(BJob* job)
|
|||||||
dependantJob->RemoveDependency(job);
|
dependantJob->RemoveDependency(job);
|
||||||
try {
|
try {
|
||||||
fQueuedJobs->insert(dependantJob);
|
fQueuedJobs->insert(dependantJob);
|
||||||
|
if (dependantJob->IsRunnable())
|
||||||
|
release_sem(fHaveRunnableJobSem);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user