Improved the interaction between job queue and manager. Partitions should now be mark busy correctly.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4223 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2003-08-03 18:39:12 +00:00
parent 13ab290504
commit 8d91b8087d
3 changed files with 191 additions and 34 deletions

View File

@ -81,6 +81,7 @@ public:
// manager must be locked
status_t AddJobQueue(KDiskDeviceJobQueue *jobQueue);
// the device must be write locked
status_t RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
status_t DeleteJobQueue(KDiskDeviceJobQueue *jobQueue);
// called when the execution is done
@ -89,6 +90,11 @@ public:
KDiskDeviceJobFactory *JobFactory() const;
// manager must *not* be locked
status_t UpdateBusyPartitions(KDiskDevice *device);
status_t UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
bool updateBusyPartitions);
// Disk Systems
// manager must be locked
@ -118,8 +124,13 @@ private:
bool _RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
status_t _UpdateBusyPartitions(KDiskDevice *device);
status_t _UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
bool updateBusyPartitions);
status_t _Scan(const char *path);
status_t _ScanPartition(KPartition *partition);
// the manager must be locked and the device write locked
struct DeviceMap;
struct DiskSystemMap;

View File

@ -187,9 +187,8 @@ KDiskDeviceJobQueue::Execute()
fSyncSemaphore = -1;
return fThread;
}
fFlags |= JOB_QUEUE_EXECUTING;
resume_thread(fThread);
// wait till the thread has resumed its work
acquire_sem(fSyncSemaphore);
return B_OK;
}
@ -301,45 +300,45 @@ KDiskDeviceJobQueue::IsPauseRequested() const
int32
KDiskDeviceJobQueue::_ThreadLoop()
{
// TODO: notifications
// mark all jobs scheduled
for (int32 i = 0; KDiskDeviceJob *job = JobAt(i); i++)
job->SetStatus(B_DISK_DEVICE_JOB_SCHEDULED);
// mark the queue executing and notify the thread waiting in Execute()
fFlags |= JOB_QUEUE_EXECUTING;
release_sem(fSyncSemaphore);
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
// main loop: process all jobs
bool failed = false;
while (KDiskDeviceJob *activeJob = ActiveJob()) {
activeJob->SetStatus(B_DISK_DEVICE_JOB_IN_PROGRESS);
manager->UpdateJobStatus(activeJob, B_DISK_DEVICE_JOB_IN_PROGRESS,
true);
status_t error = activeJob->Do();
if (error == B_OK) {
if (ManagerLocker locker = manager) {
// if canceled, mark this and all succeeding jobs canceled
if (IsCanceled()) {
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i);
i++) {
job->SetStatus(B_DISK_DEVICE_JOB_CANCELED);
}
// if canceled, simply bail out -- this and all succeeding
// jobs will be canceled
if (IsCanceled())
break;
}
// if pause was requested ignore the request
if (IsPauseRequested())
Continue();
// mark the job succeeded and go to the next one
activeJob->SetStatus(B_DISK_DEVICE_JOB_SUCCEEDED);
// go to the next job
fActiveJob++;
} else
break;
// mark the job succeeded
manager->UpdateJobStatus(activeJob, B_DISK_DEVICE_JOB_SUCCEEDED,
true);
} else {
// job failed: mark this and all succeeding jobs failed
if (ManagerLocker locker = manager) {
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i); i++)
job->SetStatus(B_DISK_DEVICE_JOB_FAILED);
}
// job failed: this and all succeeding jobs will be marked failed
failed = true;
break;
}
}
// All jobs that remain need to be marked failed or canceled.
bool updatePartitions = false;
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i); i++) {
manager->UpdateJobStatus(job, (failed ? B_DISK_DEVICE_JOB_FAILED
: B_DISK_DEVICE_JOB_CANCELED),
false);
updatePartitions = true;
}
if (updatePartitions)
manager->UpdateBusyPartitions(Device());
// tell the manager, that we are done.
if (ManagerLocker locker = manager) {
fFlags &= ~(uint32)JOB_QUEUE_EXECUTING;

View File

@ -22,6 +22,8 @@
#include "KFileSystem.h"
#include "KPartition.h"
#include "KPartitioningSystem.h"
#include "KPartitionVisitor.h"
#include "KShadowPartition.h"
// debugging
//#define DBG(x)
@ -36,6 +38,15 @@ using BPrivate::DiskDevice::KDiskDeviceJobQueue;
static const char *kPartitioningSystemPrefix = "partitioning_systems";
static const char *kFileSystemPrefix = "file_systems";
// is_active_job_status
static
bool
is_active_job_status(uint32 status)
{
return (status == B_DISK_DEVICE_JOB_SCHEDULED
|| status == B_DISK_DEVICE_JOB_IN_PROGRESS);
}
// GetPartitionID
struct GetPartitionID {
inline partition_id operator()(const KPartition *partition) const
@ -494,6 +505,11 @@ KDiskDeviceManager::CreateFileDevice(const char *filePath)
return B_NO_MEMORY;
// initialize and add the device
error = device->SetTo(filePath);
// Note: Here we are allowed to lock a device although already having
// the manager locked, since it is not yet added to the manager.
DeviceWriteLocker deviceLocker(device);
if (error == B_OK && !deviceLocker.IsLocked())
error = B_ERROR;
if (error == B_OK && !_AddDevice(device))
error = B_NO_MEMORY;
// scan device
@ -650,11 +666,20 @@ KDiskDeviceManager::AddJobQueue(KDiskDeviceJobQueue *jobQueue)
return error;
}
}
// TODO: mark the concerned partitions busy /descendant busy
// start its execution
// mark the jobs scheduled
for (int32 i = 0; KDiskDeviceJob *job = jobQueue->JobAt(i); i++)
_UpdateJobStatus(job, B_DISK_DEVICE_JOB_SCHEDULED, false);
_UpdateBusyPartitions(jobQueue->Device());
// start the execution of the queue
error = jobQueue->Execute();
if (error != B_OK)
if (error != B_OK) {
// resuming the execution failed -- mark all jobs failed and
// remove the queue
for (int32 i = 0; KDiskDeviceJob *job = jobQueue->JobAt(i); i++)
_UpdateJobStatus(job, B_DISK_DEVICE_JOB_FAILED, false);
_RemoveJobQueue(jobQueue);
_UpdateBusyPartitions(jobQueue->Device());
}
return error;
}
@ -704,6 +729,39 @@ KDiskDeviceManager::JobFactory() const
return fJobFactory;
}
// UpdateBusyPartitions
status_t
KDiskDeviceManager::UpdateBusyPartitions(KDiskDevice *device)
{
if (!device)
return B_BAD_VALUE;
if (DeviceWriteLocker deviceLocker = device) {
if (ManagerLocker locker = this)
return _UpdateBusyPartitions(device);
}
return B_ERROR;
}
// UpdateJobStatus
status_t
KDiskDeviceManager::UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
bool updateBusyPartitions)
{
// check parameters
if (!job)
return B_BAD_VALUE;
KDiskDeviceJobQueue *jobQueue = job->JobQueue();
KDiskDevice *device = (jobQueue ? jobQueue->Device() : NULL);
if (!device)
return B_BAD_VALUE;
// lock device and manager
if (DeviceWriteLocker deviceLocker = device) {
if (ManagerLocker locker = this)
return _UpdateJobStatus(job, status, updateBusyPartitions);
}
return B_ERROR;
}
// FindDiskSystem
KDiskSystem *
KDiskDeviceManager::FindDiskSystem(const char *name)
@ -801,13 +859,20 @@ KDiskDeviceManager::InitialDeviceScan()
error = _Scan("/dev/disk");
if (error != B_OK)
return error;
// scan the devices for partitions
int32 cookie = 0;
while (KDiskDevice *device = NextDevice(&cookie)) {
error = _ScanPartition(device);
if (error != B_OK)
break;
}
}
// scan the devices for partitions
int32 cookie = 0;
while (KDiskDevice *device = RegisterNextDevice(&cookie)) {
PartitionRegistrar _(device, true);
if (DeviceWriteLocker deviceLocker = device) {
if (ManagerLocker locker = this) {
error = _ScanPartition(device);
if (error != B_OK)
break;
} else
return B_ERROR;
} else
return B_ERROR;
}
return error;
}
@ -893,6 +958,88 @@ KDiskDeviceManager::_RemoveJobQueue(KDiskDeviceJobQueue *jobQueue)
return true;
}
// _UpdateBusyPartitions
status_t
KDiskDeviceManager::_UpdateBusyPartitions(KDiskDevice *device)
{
if (!device)
return B_BAD_VALUE;
// mark all partitions un-busy
struct UnmarkBusyVisitor : KPartitionVisitor {
virtual bool VisitPre(KPartition *partition)
{
partition->ClearFlags(B_PARTITION_BUSY
| B_PARTITION_DESCENDANT_BUSY);
return false;
}
} visitor;
device->VisitEachDescendant(&visitor);
if (device->ShadowPartition())
device->ShadowPartition()->VisitEachDescendant(&visitor);
// Iterate through all job queues and all jobs scheduled or in
// progress and mark their scope busy.
for (int32 cookie = 0;
KDiskDeviceJobQueue *jobQueue = NextJobQueue(&cookie); ) {
if (jobQueue->Device() != device)
continue;
for (int32 i = jobQueue->ActiveJobIndex();
KDiskDeviceJob *job = jobQueue->JobAt(i); i++) {
if (job->Status() != B_DISK_DEVICE_JOB_IN_PROGRESS
&& job->Status() == B_DISK_DEVICE_JOB_SCHEDULED) {
continue;
}
KPartition *partition = FindPartition(job->ScopeID());
if (!partition || partition->Device() != device)
continue;
partition->AddFlags(B_PARTITION_BUSY);
if (KPartition *shadow = partition->ShadowPartition())
shadow->AddFlags(B_PARTITION_BUSY);
}
}
// mark all anscestors of busy partitions descendant busy
struct MarkBusyVisitor : KPartitionVisitor {
virtual bool VisitPost(KPartition *partition)
{
if ((partition->IsBusy() || partition->IsDescendantBusy())
&& partition->Parent()) {
partition->Parent()->AddFlags(
B_PARTITION_DESCENDANT_BUSY);
}
return false;
}
} visitor2;
device->VisitEachDescendant(&visitor2);
if (device->ShadowPartition())
device->ShadowPartition()->VisitEachDescendant(&visitor2);
return B_OK;
}
// _UpdateJobStatus
status_t
KDiskDeviceManager::_UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
bool updateBusyPartitions)
{
// check parameters
if (!job)
return B_BAD_VALUE;
KDiskDeviceJobQueue *jobQueue = job->JobQueue();
KDiskDevice *device = (jobQueue ? jobQueue->Device() : NULL);
if (!device)
return B_BAD_VALUE;
if (job->Status() == status)
return B_OK;
// check migration of a schedule/in progress to a terminal state
// or vice versa
updateBusyPartitions &= (is_active_job_status(job->Status())
!= is_active_job_status(status));
// set new state and update the partitions' busy flags
job->SetStatus(status);
if (updateBusyPartitions)
return _UpdateBusyPartitions(device);
// TODO: notifications
return B_OK;
}
// _Scan
status_t
KDiskDeviceManager::_Scan(const char *path)