1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include "storbios.hxx"
24 #include "sal/types.h"
25 #include "sal/macros.h"
26 #include "sal/log.hxx"
28 #include "rtl/alloc.h"
29 #include "rtl/ref.hxx"
31 #include "osl/diagnose.h"
32 #include "osl/mutex.hxx"
34 #include "store/types.h"
36 #include "lockbyte.hxx"
37 #include "storcach.hxx"
39 using namespace store
;
41 /*========================================================================
45 *======================================================================*/
46 #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
48 struct OStoreSuperBlock
50 typedef OStorePageGuard G
;
51 typedef OStorePageDescriptor D
;
52 typedef OStorePageLink L
;
65 static const size_t theSize
= sizeof(G
) + sizeof(D
) + 2 * (sizeof(L
) + sizeof(sal_uInt32
));
69 explicit OStoreSuperBlock (sal_uInt16 nPageSize
)
70 : m_aGuard (STORE_MAGIC_SUPERBLOCK
),
71 m_aDescr (nPageSize
, nPageSize
, STORE_MINIMUM_PAGESIZE
),
72 m_nMarked (store::htonl(0)),
74 m_nUnused (store::htonl(0)),
80 bool operator== (const OStoreSuperBlock
& rhs
) const
82 return ((m_aGuard
== rhs
.m_aGuard
) &&
83 (m_aDescr
== rhs
.m_aDescr
) &&
84 (m_nMarked
== rhs
.m_nMarked
) &&
85 (m_aMarked
== rhs
.m_aMarked
) &&
86 (m_nUnused
== rhs
.m_nUnused
) &&
87 (m_aUnused
== rhs
.m_aUnused
) );
90 /** unused(Count|Head|Insert|Remove|Reset).
92 sal_uInt32
unusedCount() const
94 return store::ntohl(m_nUnused
);
96 const L
& unusedHead() const
100 void unusedInsert (const L
& rLink
)
102 sal_uInt32 nUnused
= unusedCount();
103 m_nUnused
= store::htonl(nUnused
+ 1);
106 void unusedRemove (const L
& rLink
)
108 sal_uInt32 nUnused
= unusedCount();
109 m_nUnused
= store::htonl(nUnused
- 1);
114 m_nUnused
= store::htonl(0);
118 /** guard (external representation).
122 sal_uInt32 nCRC32
= 0;
123 nCRC32
= rtl_crc32 (nCRC32
, &m_aGuard
.m_nMagic
, sizeof(sal_uInt32
));
124 nCRC32
= rtl_crc32 (nCRC32
, &m_aDescr
, static_cast<sal_uInt32
>(theSize
- sizeof(G
)));
125 m_aGuard
.m_nCRC32
= store::htonl(nCRC32
);
128 /** verify (external representation).
130 storeError
verify() const
132 sal_uInt32 nMagic
= store::ntohl(m_aGuard
.m_nMagic
);
133 if (nMagic
!= STORE_MAGIC_SUPERBLOCK
)
134 return store_E_WrongFormat
;
136 sal_uInt32 nCRC32
= 0;
137 nCRC32
= rtl_crc32 (nCRC32
, &m_aGuard
.m_nMagic
, sizeof(sal_uInt32
));
138 nCRC32
= rtl_crc32 (nCRC32
, &m_aDescr
, static_cast<sal_uInt32
>(theSize
- sizeof(G
)));
139 if (m_aGuard
.m_nCRC32
!= store::htonl(nCRC32
))
140 return store_E_InvalidChecksum
;
146 /*========================================================================
148 * SuperBlockPage interface.
150 *======================================================================*/
154 struct SuperBlockPage
156 typedef OStoreSuperBlock SuperBlock
;
160 SuperBlock m_aSuperOne
;
161 SuperBlock m_aSuperTwo
;
165 static const size_t theSize
= 2 * SuperBlock::theSize
;
166 static const sal_uInt16 thePageSize
= theSize
;
167 static_assert(STORE_MINIMUM_PAGESIZE
>= thePageSize
, "must be at least thePageSize");
171 static void * operator new (size_t n
)
173 return rtl_allocateMemory (sal::static_int_cast
<sal_Size
>(n
));
175 static void operator delete (void * p
)
180 static void * operator new (SAL_UNUSED_PARAMETER
size_t, sal_uInt16 nPageSize
)
182 return rtl_allocateZeroMemory (sal::static_int_cast
<sal_Size
>(nPageSize
));
184 static void operator delete (void * p
, SAL_UNUSED_PARAMETER sal_uInt16
)
191 explicit SuperBlockPage (sal_uInt16 nPageSize
= thePageSize
)
192 : m_aSuperOne(nPageSize
),
193 m_aSuperTwo(nPageSize
)
198 storeError
save (OStorePageBIOS
& rBIOS
, sal_uInt32 nSize
= theSize
)
201 m_aSuperTwo
= m_aSuperOne
;
202 return rBIOS
.write (0, this, nSize
);
207 storeError
unusedHead (
208 OStorePageBIOS
& rBIOS
,
209 PageData
& rPageHead
);
211 storeError
unusedPop (
212 OStorePageBIOS
& rBIOS
,
213 PageData
const & rPageHead
);
215 storeError
unusedPush (
216 OStorePageBIOS
& rBIOS
,
219 /** verify (with repair).
221 storeError
verify (OStorePageBIOS
& rBIOS
);
226 /*========================================================================
228 * SuperBlockPage implementation.
230 *======================================================================*/
232 * unusedHead(): get freelist head (alloc page, step 1).
234 storeError
SuperBlockPage::unusedHead (OStorePageBIOS
& rBIOS
, PageData
& rPageHead
)
236 storeError eErrCode
= verify (rBIOS
);
237 if (eErrCode
!= store_E_None
)
240 // Check freelist head.
241 OStorePageLink
const aListHead (m_aSuperOne
.unusedHead());
242 if (aListHead
.location() == 0)
244 // Freelist empty, see SuperBlock::ctor().
245 rPageHead
.location (STORE_PAGE_NULL
);
250 eErrCode
= rBIOS
.read (aListHead
.location(), &rPageHead
, PageData::theSize
);
251 if (eErrCode
!= store_E_None
)
254 eErrCode
= rPageHead
.verify (aListHead
.location());
255 if (eErrCode
!= store_E_None
)
258 // Verify page is unused.
259 sal_uInt32
const nAddr
= rPageHead
.m_aUnused
.location();
260 if (nAddr
== STORE_PAGE_NULL
)
262 SAL_WARN("store", "store::SuperBlock::unusedHead(): page not free");
265 rPageHead
.location (STORE_PAGE_NULL
);
267 // Recovery: Reset freelist to empty.
268 m_aSuperOne
.unusedReset();
269 eErrCode
= save (rBIOS
);
275 * unusedPop(): pop freelist head (alloc page, step 2).
277 storeError
SuperBlockPage::unusedPop (OStorePageBIOS
& rBIOS
, PageData
const & rPageHead
)
279 sal_uInt32
const nAddr
= rPageHead
.m_aUnused
.location();
280 OSL_PRECOND(nAddr
!= STORE_PAGE_NULL
, "store::SuperBlock::unusedPop(): page not free");
281 if (nAddr
== STORE_PAGE_NULL
)
282 return store_E_CantSeek
;
284 // Pop from FreeList.
285 OStorePageLink
const aListHead (nAddr
);
286 m_aSuperOne
.unusedRemove (aListHead
);
291 * unusedPush(): push new freelist head.
293 storeError
SuperBlockPage::unusedPush (OStorePageBIOS
& rBIOS
, sal_uInt32 nAddr
)
295 storeError eErrCode
= verify (rBIOS
);
296 if (eErrCode
!= store_E_None
)
300 eErrCode
= rBIOS
.read (nAddr
, &aPageHead
, PageData::theSize
);
301 if (eErrCode
!= store_E_None
)
304 eErrCode
= aPageHead
.verify (nAddr
);
305 if (eErrCode
!= store_E_None
)
308 aPageHead
.m_aUnused
= m_aSuperOne
.unusedHead();
309 aPageHead
.guard (nAddr
);
311 eErrCode
= rBIOS
.write (nAddr
, &aPageHead
, PageData::theSize
);
312 if (eErrCode
!= store_E_None
)
315 OStorePageLink
const aListHead (nAddr
);
316 m_aSuperOne
.unusedInsert(aListHead
);
321 * verify (with repair).
323 storeError
SuperBlockPage::verify (OStorePageBIOS
& rBIOS
)
326 storeError eErrCode
= m_aSuperOne
.verify();
327 if (eErrCode
== store_E_None
)
329 // Ok. Verify 2nd copy.
330 eErrCode
= m_aSuperTwo
.verify();
331 if (eErrCode
== store_E_None
)
333 // Ok. Ensure identical copies (1st copy wins).
334 if (!(m_aSuperOne
== m_aSuperTwo
))
336 // Different. Replace 2nd copy with 1st copy.
337 m_aSuperTwo
= m_aSuperOne
;
340 if (rBIOS
.isWriteable())
341 eErrCode
= rBIOS
.write (0, this, theSize
);
343 eErrCode
= store_E_None
;
348 // Failure. Replace 2nd copy with 1st copy.
349 m_aSuperTwo
= m_aSuperOne
;
352 if (rBIOS
.isWriteable())
353 eErrCode
= rBIOS
.write (0, this, theSize
);
355 eErrCode
= store_E_None
;
360 // Failure. Verify 2nd copy.
361 eErrCode
= m_aSuperTwo
.verify();
362 if (eErrCode
== store_E_None
)
364 // Ok. Replace 1st copy with 2nd copy.
365 m_aSuperOne
= m_aSuperTwo
;
368 if (rBIOS
.isWriteable())
369 eErrCode
= rBIOS
.write (0, this, theSize
);
371 eErrCode
= store_E_None
;
376 OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
384 /*========================================================================
386 * OStorePageBIOS::Ace implementation.
388 *======================================================================*/
389 OStorePageBIOS::Ace::Ace()
390 : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL
), m_used (0)
393 OStorePageBIOS::Ace::~Ace()
395 m_next
->m_prev
= m_prev
;
396 m_prev
->m_next
= m_next
;
400 SAL_CALL
OStorePageBIOS::Ace::constructor (
401 void * obj
, SAL_UNUSED_PARAMETER
void * /* arg */)
403 Ace
* ace
= static_cast<Ace
*>(obj
);
404 ace
->m_next
= ace
->m_prev
= ace
;
408 OStorePageBIOS::Ace
*
409 OStorePageBIOS::Ace::find (OStorePageBIOS::Ace
* head
, sal_uInt32 addr
)
411 OStorePageBIOS::Ace
* entry
;
412 for (entry
= head
->m_next
; entry
!= head
; entry
= entry
->m_next
)
414 if (entry
->m_addr
>= addr
)
421 OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace
* head
, OStorePageBIOS::Ace
* entry
)
423 // insert entry at queue tail (before head).
424 entry
->m_next
= head
;
425 entry
->m_prev
= head
->m_prev
;
426 head
->m_prev
= entry
;
427 entry
->m_prev
->m_next
= entry
;
430 /*========================================================================
432 * OStorePageBIOS::AceCache interface.
434 *======================================================================*/
438 class OStorePageBIOS::AceCache
440 rtl_cache_type
* m_ace_cache
;
443 static AceCache
& get();
445 OStorePageBIOS::Ace
*
446 create (sal_uInt32 addr
);
449 destroy (OStorePageBIOS::Ace
* ace
);
458 /*========================================================================
460 * OStorePageBIOS::AceCache implementation.
462 *======================================================================*/
463 extern "C" typedef int (SAL_CALL
* ace_constructor_type
)(void*,void*);
465 OStorePageBIOS::AceCache
&
466 OStorePageBIOS::AceCache::get()
468 static AceCache g_ace_cache
;
472 OStorePageBIOS::AceCache::AceCache()
474 m_ace_cache
= rtl_cache_create (
476 sizeof (OStorePageBIOS::Ace
),
478 reinterpret_cast<ace_constructor_type
>( OStorePageBIOS::Ace::constructor
),
479 nullptr, // destructor,
482 nullptr, // default source,
487 OStorePageBIOS::AceCache::~AceCache()
489 rtl_cache_destroy (m_ace_cache
);
490 m_ace_cache
= nullptr;
493 OStorePageBIOS::Ace
*
494 OStorePageBIOS::AceCache::create (sal_uInt32 addr
)
496 Ace
* ace
= static_cast<Ace
*>(rtl_cache_alloc (m_ace_cache
));
499 // verify invariant state.
500 OSL_ASSERT((ace
->m_next
== ace
) && (ace
->m_prev
== ace
));
510 OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace
* ace
)
514 // remove from queue (if any).
515 ace
->m_next
->m_prev
= ace
->m_prev
;
516 ace
->m_prev
->m_next
= ace
->m_next
;
518 // restore invariant state.
519 ace
->m_next
= ace
->m_prev
= ace
;
522 rtl_cache_free (m_ace_cache
, ace
);
526 /*========================================================================
528 * OStorePageBIOS implementation.
530 *======================================================================*/
534 OStorePageBIOS::OStorePageBIOS()
535 : m_xLockBytes (nullptr),
544 OStorePageBIOS::~OStorePageBIOS()
553 storeError
OStorePageBIOS::initialize (
554 ILockBytes
* pLockBytes
,
555 storeAccessMode eAccessMode
,
556 sal_uInt16
& rnPageSize
)
558 // Acquire exclusive access.
559 osl::MutexGuard
aGuard (m_aMutex
);
562 storeError eErrCode
= initialize_Impl (pLockBytes
, eAccessMode
, rnPageSize
);
563 if (eErrCode
!= store_E_None
)
573 * Internal: Precond: exclusive access.
575 storeError
OStorePageBIOS::initialize_Impl (
576 ILockBytes
* pLockBytes
,
577 storeAccessMode eAccessMode
,
578 sal_uInt16
& rnPageSize
)
584 m_xLockBytes
= pLockBytes
;
585 if (!m_xLockBytes
.is())
586 return store_E_InvalidParameter
;
587 m_bWriteable
= (eAccessMode
!= storeAccessMode::ReadOnly
);
589 // Check access mode.
590 storeError eErrCode
= store_E_None
;
591 if (eAccessMode
!= storeAccessMode::Create
)
593 // Load SuperBlock page.
594 if ((m_pSuper
= new SuperBlockPage()) == nullptr)
595 return store_E_OutOfMemory
;
597 eErrCode
= read (0, m_pSuper
, SuperBlockPage::theSize
);
598 if (eErrCode
== store_E_None
)
600 // Verify SuperBlock page (with repair).
601 eErrCode
= m_pSuper
->verify (*this);
606 // Truncate to zero length.
607 eErrCode
= m_xLockBytes
->setSize(0);
608 if (eErrCode
!= store_E_None
)
611 // Mark as not existing.
612 eErrCode
= store_E_NotExists
;
615 if (eErrCode
!= store_E_None
)
618 if (eErrCode
!= store_E_NotExists
)
622 if (eAccessMode
== storeAccessMode::ReadOnly
)
623 return store_E_NotExists
;
624 if (eAccessMode
== storeAccessMode::ReadWrite
)
625 return store_E_NotExists
;
628 if ((STORE_MINIMUM_PAGESIZE
> rnPageSize
) || (rnPageSize
> STORE_MAXIMUM_PAGESIZE
))
629 return store_E_InvalidParameter
;
630 rnPageSize
= ((rnPageSize
+ STORE_MINIMUM_PAGESIZE
- 1) & ~(STORE_MINIMUM_PAGESIZE
- 1));
632 // Create initial page (w/ SuperBlock).
633 if ((m_pSuper
= new(rnPageSize
) SuperBlockPage(rnPageSize
)) == nullptr)
634 return store_E_OutOfMemory
;
635 eErrCode
= m_pSuper
->save (*this, rnPageSize
);
637 if (eErrCode
== store_E_None
)
640 rnPageSize
= store::ntohs(m_pSuper
->m_aSuperOne
.m_aDescr
.m_nSize
);
642 // Create page allocator.
643 eErrCode
= m_xLockBytes
->initialize (m_xAllocator
, rnPageSize
);
644 if (eErrCode
!= store_E_None
)
647 // Create page cache.
648 eErrCode
= PageCache_createInstance (m_xCache
, rnPageSize
);
655 * Internal: Precond: exclusive access.
657 void OStorePageBIOS::cleanup_Impl()
659 // Check referer count.
660 if (m_ace_head
.m_used
> 0)
662 // Report remaining referer count.
663 SAL_INFO("store", "referer count: " << m_ace_head
.m_used
);
664 for (Ace
* ace
= m_ace_head
.m_next
; ace
!= &m_ace_head
; ace
= m_ace_head
.m_next
)
666 m_ace_head
.m_used
-= ace
->m_used
;
667 AceCache::get().destroy (ace
);
669 OSL_ENSURE(m_ace_head
.m_used
== 0, "store::PageBIOS::cleanup_Impl(): logic error");
672 // Release SuperBlock page.
676 // Release PageCache.
679 // Release PageAllocator.
680 m_xAllocator
.clear();
682 // Release LockBytes.
683 m_xLockBytes
.clear();
688 * Low Level: Precond: initialized, exclusive access.
690 storeError
OStorePageBIOS::read (
691 sal_uInt32 nAddr
, void *pData
, sal_uInt32 nSize
)
694 if (!m_xLockBytes
.is())
695 return store_E_InvalidAccess
;
698 return m_xLockBytes
->readAt (nAddr
, pData
, nSize
);
703 * Low Level: Precond: initialized, writeable, exclusive access.
705 storeError
OStorePageBIOS::write (
706 sal_uInt32 nAddr
, const void *pData
, sal_uInt32 nSize
)
709 if (!m_xLockBytes
.is())
710 return store_E_InvalidAccess
;
712 return store_E_AccessViolation
;
715 return m_xLockBytes
->writeAt (nAddr
, pData
, nSize
);
720 * Precond: initialized.
722 storeError
OStorePageBIOS::acquirePage (
723 const OStorePageDescriptor
& rDescr
, storeAccessMode eMode
)
725 // Acquire exclusive access.
726 osl::MutexGuard
aGuard (m_aMutex
);
729 if (!m_xLockBytes
.is())
730 return store_E_InvalidAccess
;
732 // Check access mode.
733 if (!(m_bWriteable
|| (eMode
== storeAccessMode::ReadOnly
)))
734 return store_E_AccessViolation
;
736 // Find access control list entry.
737 Ace
* ace
= Ace::find (&m_ace_head
, rDescr
.m_nAddr
);
738 if (ace
->m_addr
== rDescr
.m_nAddr
)
740 // Acquire existing entry (with ShareDenyWrite).
741 if (eMode
== storeAccessMode::ReadOnly
)
744 return store_E_AccessViolation
;
749 Ace
* entry
= AceCache::get().create (rDescr
.m_nAddr
);
751 return store_E_OutOfMemory
;
752 Ace::insert (ace
, entry
);
755 // Increment total referer count and finish.
756 m_ace_head
.m_used
+= 1;
762 * Precond: initialized.
764 storeError
OStorePageBIOS::releasePage (const OStorePageDescriptor
& rDescr
)
766 // Acquire exclusive access.
767 osl::MutexGuard
aGuard (m_aMutex
);
770 if (!m_xLockBytes
.is())
771 return store_E_InvalidAccess
;
773 // Find access control list entry.
774 Ace
* ace
= Ace::find (&m_ace_head
, rDescr
.m_nAddr
);
775 if (ace
->m_addr
!= rDescr
.m_nAddr
)
776 return store_E_NotExists
;
778 // Release existing entry.
782 AceCache::get().destroy (ace
);
784 // Decrement total referer count and finish.
785 m_ace_head
.m_used
-= 1;
791 * Precond: initialized, writeable.
793 storeError
OStorePageBIOS::allocate (
794 OStorePageObject
& rPage
)
796 // Acquire exclusive access.
797 osl::MutexGuard
aGuard (m_aMutex
);
800 if (!m_xLockBytes
.is())
801 return store_E_InvalidAccess
;
803 return store_E_AccessViolation
;
805 // Check allocation type.
806 storeError eErrCode
= store_E_None
;
807 // Try freelist head.
809 eErrCode
= m_pSuper
->unusedHead (*this, aPageHead
);
810 if (eErrCode
!= store_E_None
)
813 sal_uInt32
const nAddr
= aPageHead
.location();
814 if (nAddr
!= STORE_PAGE_NULL
)
817 eErrCode
= saveObjectAt_Impl (rPage
, nAddr
);
818 if (eErrCode
!= store_E_None
)
821 // Pop freelist head and finish.
822 return m_pSuper
->unusedPop (*this, aPageHead
);
825 // Allocate from EOF. Determine current size.
826 sal_uInt32 nSize
= STORE_PAGE_NULL
;
827 eErrCode
= m_xLockBytes
->getSize (nSize
);
828 if (eErrCode
!= store_E_None
)
831 // Save page at current EOF.
832 return saveObjectAt_Impl (rPage
, nSize
);
837 * Precond: initialized, writeable.
839 storeError
OStorePageBIOS::free (sal_uInt32 nAddr
)
841 // Acquire exclusive access.
842 osl::MutexGuard
aGuard (m_aMutex
);
845 if (!m_xLockBytes
.is())
846 return store_E_InvalidAccess
;
848 return store_E_AccessViolation
;
851 (void) m_xCache
->removePageAt (nAddr
);
853 // Push onto freelist.
854 return m_pSuper
->unusedPush (*this, nAddr
);
859 * Precond: initialized, readable.
861 storeError
OStorePageBIOS::loadObjectAt (OStorePageObject
& rPage
, sal_uInt32 nAddr
)
863 // Acquire exclusive access.
864 osl::MutexGuard
aGuard (m_aMutex
);
867 if (!m_xLockBytes
.is())
868 return store_E_InvalidAccess
;
870 return loadObjectAt_Impl (rPage
, nAddr
);
875 * Internal: Precond: initialized, readable, exclusive access.
877 storeError
OStorePageBIOS::loadObjectAt_Impl (OStorePageObject
& rPage
, sal_uInt32 nAddr
)
879 storeError eErrCode
= m_xCache
->lookupPageAt (rPage
.get(), nAddr
);
880 if (eErrCode
!= store_E_NotExists
)
884 eErrCode
= m_xLockBytes
->readPageAt (rPage
.get(), nAddr
);
885 if (eErrCode
!= store_E_None
)
889 eErrCode
= rPage
.verify (nAddr
);
890 if (eErrCode
!= store_E_None
)
893 // Mark page as clean.
897 return m_xCache
->insertPageAt (rPage
.get(), nAddr
);
902 * Precond: initialized, writeable.
904 storeError
OStorePageBIOS::saveObjectAt (OStorePageObject
& rPage
, sal_uInt32 nAddr
)
906 // Acquire exclusive access.
907 osl::MutexGuard
aGuard (m_aMutex
);
910 if (!m_xLockBytes
.is())
911 return store_E_InvalidAccess
;
913 return store_E_AccessViolation
;
916 return saveObjectAt_Impl (rPage
, nAddr
);
921 * Internal: Precond: initialized, writeable, exclusive access.
923 storeError
OStorePageBIOS::saveObjectAt_Impl (OStorePageObject
& rPage
, sal_uInt32 nAddr
)
925 // Guard page (incl. set location).
926 storeError eErrCode
= rPage
.guard (nAddr
);
927 if (eErrCode
!= store_E_None
)
931 eErrCode
= m_xLockBytes
->writePageAt(rPage
.get(), nAddr
);
932 if (eErrCode
!= store_E_None
)
935 // Mark page as clean.
939 return m_xCache
->updatePageAt (rPage
.get(), nAddr
);
946 storeError
OStorePageBIOS::close()
948 // Acquire exclusive access.
949 osl::MutexGuard
aGuard (m_aMutex
);
960 * Precond: initialized.
962 storeError
OStorePageBIOS::flush()
964 // Acquire exclusive access.
965 osl::MutexGuard
aGuard (m_aMutex
);
968 if (!m_xLockBytes
.is())
969 return store_E_InvalidAccess
;
971 // Flush LockBytes and finish.
972 return m_xLockBytes
->flush();
975 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */