* Added a simple mechanism to wait for events to VMCache. WaitForPageEvents()
waits for certain events on a given page, NotifyPageEvents() wakes up waiting threads respectively. * Used the new feature instead of condition variables for waiting on busy pages. We save publishing and unpublishing of a condition variable whenever a page is marked busy. There's only something to do, if there's at least one thread waiting in the list of the respective cache. The general assumption is that this is only rarely the case and even if it happens, there should be only very few threads. * Added an apparently missing notification in cache_io(). At least I didn't see the reason for it not being there. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34537 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+9
-23
@@ -114,7 +114,6 @@ PrecacheIO::PrecacheIO(file_cache_ref* ref, off_t offset, size_t size)
|
||||
fRef(ref),
|
||||
fCache(ref->cache),
|
||||
fPages(NULL),
|
||||
fBusyConditions(NULL),
|
||||
fVecs(NULL),
|
||||
fOffset(offset),
|
||||
fVecCount(0),
|
||||
@@ -128,7 +127,6 @@ PrecacheIO::PrecacheIO(file_cache_ref* ref, off_t offset, size_t size)
|
||||
PrecacheIO::~PrecacheIO()
|
||||
{
|
||||
delete[] fPages;
|
||||
delete[] fBusyConditions;
|
||||
delete[] fVecs;
|
||||
fCache->ReleaseRefLocked();
|
||||
}
|
||||
@@ -144,10 +142,6 @@ PrecacheIO::Prepare()
|
||||
if (fPages == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fBusyConditions = new(std::nothrow) ConditionVariable[fPageCount];
|
||||
if (fBusyConditions == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fVecs = new(std::nothrow) iovec[fPageCount];
|
||||
if (fVecs == NULL)
|
||||
return B_NO_MEMORY;
|
||||
@@ -159,7 +153,6 @@ PrecacheIO::Prepare()
|
||||
if (page == NULL)
|
||||
break;
|
||||
|
||||
fBusyConditions[i].Publish(page, "page");
|
||||
fCache->InsertPage(page, fOffset + pos);
|
||||
|
||||
add_to_iovec(fVecs, fVecCount, fPageCount,
|
||||
@@ -170,7 +163,7 @@ PrecacheIO::Prepare()
|
||||
if (i != fPageCount) {
|
||||
// allocating pages failed
|
||||
while (i-- > 0) {
|
||||
fBusyConditions[i].Unpublish();
|
||||
fCache->NotifyPageEvents(fPages[i], PAGE_EVENT_NOT_BUSY);
|
||||
fCache->RemovePage(fPages[i]);
|
||||
vm_page_set_state(fPages[i], PAGE_STATE_FREE);
|
||||
}
|
||||
@@ -215,12 +208,12 @@ PrecacheIO::IOFinished(status_t status, bool partialTransfer,
|
||||
}
|
||||
|
||||
fPages[i]->state = PAGE_STATE_ACTIVE;
|
||||
fBusyConditions[i].Unpublish();
|
||||
fCache->NotifyPageEvents(fPages[i], PAGE_EVENT_NOT_BUSY);
|
||||
}
|
||||
|
||||
// Free pages after failed I/O
|
||||
for (uint32 i = pagesTransferred; i < fPageCount; i++) {
|
||||
fBusyConditions[i].Unpublish();
|
||||
fCache->NotifyPageEvents(fPages[i], PAGE_EVENT_NOT_BUSY);
|
||||
fCache->RemovePage(fPages[i]);
|
||||
vm_page_set_state(fPages[i], PAGE_STATE_FREE);
|
||||
}
|
||||
@@ -383,7 +376,6 @@ read_into_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
|
||||
size_t numBytes = PAGE_ALIGN(pageOffset + bufferSize);
|
||||
vm_page* pages[MAX_IO_VECS];
|
||||
ConditionVariable busyConditions[MAX_IO_VECS];
|
||||
int32 pageIndex = 0;
|
||||
|
||||
// allocate pages for the cache and mark them busy
|
||||
@@ -393,8 +385,6 @@ read_into_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
if (page == NULL)
|
||||
panic("no more pages!");
|
||||
|
||||
busyConditions[pageIndex - 1].Publish(page, "page");
|
||||
|
||||
cache->InsertPage(page, offset + pos);
|
||||
|
||||
add_to_iovec(vecs, vecCount, MAX_IO_VECS,
|
||||
@@ -417,7 +407,7 @@ read_into_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
cache->Lock();
|
||||
|
||||
for (int32 i = 0; i < pageIndex; i++) {
|
||||
busyConditions[i].Unpublish();
|
||||
cache->NotifyPageEvents(pages[i], PAGE_EVENT_NOT_BUSY);
|
||||
cache->RemovePage(pages[i]);
|
||||
vm_page_set_state(pages[i], PAGE_STATE_FREE);
|
||||
}
|
||||
@@ -448,7 +438,7 @@ read_into_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
for (int32 i = pageIndex; i-- > 0;) {
|
||||
pages[i]->state = PAGE_STATE_ACTIVE;
|
||||
|
||||
busyConditions[i].Unpublish();
|
||||
cache->NotifyPageEvents(pages[i], PAGE_EVENT_NOT_BUSY);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
@@ -504,7 +494,6 @@ write_to_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
vm_page* pages[MAX_IO_VECS];
|
||||
int32 pageIndex = 0;
|
||||
status_t status = B_OK;
|
||||
ConditionVariable busyConditions[MAX_IO_VECS];
|
||||
|
||||
// ToDo: this should be settable somewhere
|
||||
bool writeThrough = false;
|
||||
@@ -518,7 +507,6 @@ write_to_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
// in cache_io()
|
||||
vm_page* page = pages[pageIndex++] = vm_page_allocate_page(
|
||||
PAGE_STATE_FREE, true);
|
||||
busyConditions[pageIndex - 1].Publish(page, "page");
|
||||
|
||||
ref->cache->InsertPage(page, offset + pos);
|
||||
|
||||
@@ -616,7 +604,7 @@ write_to_cache(file_cache_ref* ref, void* cookie, off_t offset,
|
||||
|
||||
// make the pages accessible in the cache
|
||||
for (int32 i = pageIndex; i-- > 0;) {
|
||||
busyConditions[i].Unpublish();
|
||||
ref->cache->NotifyPageEvents(pages[i], PAGE_EVENT_NOT_BUSY);
|
||||
|
||||
if (writeThrough)
|
||||
pages[i]->state = PAGE_STATE_ACTIVE;
|
||||
@@ -796,11 +784,7 @@ cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer,
|
||||
return status;
|
||||
|
||||
if (page->state == PAGE_STATE_BUSY) {
|
||||
ConditionVariableEntry entry;
|
||||
entry.Add(page);
|
||||
locker.Unlock();
|
||||
entry.Wait();
|
||||
locker.Lock();
|
||||
cache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -845,6 +829,8 @@ cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer,
|
||||
page->state = oldPageState;
|
||||
if (doWrite && page->state != PAGE_STATE_MODIFIED)
|
||||
vm_page_set_state(page, PAGE_STATE_MODIFIED);
|
||||
|
||||
cache->NotifyPageEvents(page, PAGE_EVENT_NOT_BUSY);
|
||||
}
|
||||
|
||||
if (bytesLeft <= bytesInPage) {
|
||||
|
||||
Reference in New Issue
Block a user