Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*==================================================================================================
     18 
     19     Source Name: SYNCML_DM_Lock.cc
     20 
     21     General Description: Implementation of the DMFileLockingThread, Clock and  DMLockManager classes
     22 
     23 ==================================================================================================*/
     24 
     25 #include "dmLock.h"
     26 #include "xpl_Logger.h"
     27 #include "xpl_dm_Manager.h"
     28 #include "dm_tree_class.H"
     29 
     30 #ifndef DM_NO_LOCKING
     31 // memory aging check interval in seconds
     32 #define DEFAULT_AGING_CHECK_INTERVAL 60
     33 
     34 // Static member
     35 DMCriticalSection DMLock::m_csLock;
     36 
     37 DMFileLockingThread::DMFileLockingThread( DMLockManager* pLockManager )
     38 {
     39     m_nReady=SYNCML_DM_THREAD_STARTING;
     40     m_pLockManager = pLockManager;
     41 
     42     m_nAgingCheckInterval = DEFAULT_AGING_CHECK_INTERVAL;
     43     CPCHAR dm_aging_env = XPL_DM_GetEnv(SYNCML_DM_MEMORY_AGING_INTERVAL);
     44     if ( dm_aging_env != NULL) {
     45         INT32 interval = DmAtoi(dm_aging_env);
     46         if (interval >= 0) {
     47             m_nAgingCheckInterval = interval;
     48         } else {
     49             m_nAgingCheckInterval = 0;
     50         }
     51     }
     52 }
     53 
     54 void* DMFileLockingThread ::Run()
     55 {
     56   BOOLEAN bDone = FALSE;
     57   DMVector< DMFileLockParam > aMessages;
     58 
     59   m_nReady = SYNCML_DM_THREAD_STARTED;
     60   INT32 nAgingCheck = m_nAgingCheckInterval;
     61   INT32 nElapsed = 0;
     62   XPL_CLK_CLOCK_T startTime, endTime;
     63 
     64   while(!bDone)
     65   {
     66     INT64 nTimeoutMS;
     67     if (m_nAgingCheckInterval <= 0)
     68     {
     69       nTimeoutMS = (aMessages.size() == 0 ? DM_WAIT_FOREVER : 100 );
     70     }
     71     else
     72     {
     73         nTimeoutMS = (aMessages.size()==0 ? (nAgingCheck * 1000) : 100 );
     74     }
     75     startTime = XPL_CLK_GetClock();
     76     DMThreadEvent evt;
     77 
     78     if ( m_pLockManager->GetQueue()->Wait(nTimeoutMS, evt))
     79     {
     80       switch ( evt.GetEventType() )
     81       {
     82         case SYNCML_DM_THREAD_EVENT_TYPE_TIMEOUT:
     83           dmTreeObj.GetLockContextManager().ReleaseAll();
     84           break;
     85         case SYNCML_DM_THREAD_EVENT_TYPE_FILELOCK:
     86           {
     87               DMFileLockParam* ptr = (DMFileLockParam*)evt.GetData();
     88               aMessages.push_back( *ptr );
     89               DmFreeMem( ptr );
     90               break;
     91           }
     92         case SYNCML_DM_THREAD_EVENT_TYPE_SHUTDOWN:
     93           bDone = true;
     94           break;
     95         default:
     96         case SYNCML_DM_THREAD_EVENT_TYPE_NONE:
     97         {
     98           // DM: just to supress warning, do nothing here
     99           break;
    100         }
    101       }
    102 
    103       endTime = XPL_CLK_GetClock();
    104       nAgingCheck -= (int)(endTime - startTime);
    105       nElapsed += (int)(endTime - startTime);
    106     }
    107     else
    108     {
    109 
    110       endTime = XPL_CLK_GetClock();
    111       nElapsed += (int)(endTime - startTime);
    112 
    113       if ( (nTimeoutMS == nAgingCheck * 1000) &&
    114            (!m_pLockManager->GetQueue()->IsTimerSet()) )
    115       {
    116         XPL_LOG_DM_TMN_Debug(("Memory aging time out = %d sec.\n", nElapsed));
    117         dmTreeObj.CheckMemoryAging();
    118         nAgingCheck = m_nAgingCheckInterval;
    119         nElapsed = 0;
    120       }
    121       else
    122       {
    123           nAgingCheck -= (int)(endTime - startTime);
    124       }
    125     }
    126 
    127     if (nAgingCheck < 1)
    128     {
    129         endTime = XPL_CLK_GetClock();
    130                XPL_LOG_DM_TMN_Debug(("Memory aging time out = %d sec.\n", nElapsed ));
    131         nAgingCheck = 1;
    132     }
    133 
    134     // try to lock/unlock all postponed requests:
    135     for ( int i = 0; i < aMessages.size(); i++ ) {
    136       DMFileLockParam& pFileLockMsg = aMessages[i];
    137 
    138       if ( m_pLockManager->ProcessLockRequest( &pFileLockMsg ) ) {
    139         aMessages.remove(i);
    140         i--;  // don't skip next
    141       }
    142     }
    143   }
    144 
    145   m_nReady = SYNCML_DM_THREAD_STARTING;
    146 
    147   return NULL;
    148 }
    149 
    150 DMLock::DMLock()
    151 {
    152   m_pFile = NULL;
    153   m_nReadWriteCounter = 0;
    154 }
    155 
    156 DMLock::~DMLock()
    157 {
    158   if (m_pFile)
    159   {
    160     Destroy();
    161   }
    162 }
    163 
    164 SYNCML_DM_RET_STATUS_T
    165 DMLock::Init( CPCHAR p_LockFileName)
    166 {
    167   m_nReadWriteCounter = 0;
    168   m_pFile = new DMFileHandler(p_LockFileName);
    169 
    170   SYNCML_DM_RET_STATUS_T nRes =  m_pFile->open(XPL_FS_FILE_RDWR);
    171 
    172   if ( nRes != SYNCML_DM_SUCCESS )
    173     Destroy();
    174 
    175   return nRes;
    176 }
    177 
    178 SYNCML_DM_RET_STATUS_T
    179 DMLock::Destroy(void)
    180 {
    181   if (!m_pFile)
    182     return SYNCML_DM_SUCCESS;
    183 
    184   m_pFile->unlock();
    185   m_pFile->close();
    186   delete m_pFile;
    187   m_pFile = NULL;
    188 
    189   return SYNCML_DM_SUCCESS;
    190 }
    191 
    192 SYNCML_DM_RET_STATUS_T
    193 DMLock::Lock( SYNCML_DM_TREE_LOCK_TYPE_T eLockType)
    194 {
    195     DMSingleLock oLock( DMLock::m_csLock );
    196 
    197     INT32 nPrevCounter = m_nReadWriteCounter;
    198     SYNCML_DM_RET_STATUS_T nRes = SYNCML_DM_SUCCESS;
    199 
    200     if ( eLockType == SYNCML_DM_LOCK_TYPE_EXCLUSIVE )
    201     {
    202         if ( m_nReadWriteCounter != 0 )
    203             return SYNCML_DM_LOCK_TRY_AGAIN; // not available
    204 
    205         m_nReadWriteCounter = -1; // writer
    206     }
    207     else
    208     { // shared lock
    209         if ( m_nReadWriteCounter < 0 )
    210             return SYNCML_DM_LOCK_TRY_AGAIN; // writer in progress
    211 
    212         m_nReadWriteCounter++; // reader
    213     }
    214 
    215 
    216     if ( m_nReadWriteCounter <= 1 )
    217     { // only first reader/writer should lock the file
    218         if (!m_pFile)
    219             return SYNCML_DM_FAIL;
    220 
    221         if ( eLockType == SYNCML_DM_LOCK_TYPE_EXCLUSIVE )
    222             nRes = m_pFile->lock( TRUE );
    223         else
    224             nRes = m_pFile->lock( FALSE );
    225 
    226         if ( nRes == SYNCML_DM_LOCK_TRY_AGAIN )
    227             m_nReadWriteCounter = nPrevCounter;
    228     }
    229 
    230     return nRes;
    231 }
    232 
    233 
    234 SYNCML_DM_RET_STATUS_T DMLock::Unlock()
    235 {
    236   SYNCML_DM_RET_STATUS_T nRes = SYNCML_DM_SUCCESS;
    237   DMSingleLock oLock( DMLock::m_csLock );
    238 
    239   if ( m_pFile && IsLastLock() )
    240     nRes = m_pFile->unlock();
    241 
    242   if ( m_nReadWriteCounter < 0 )
    243     m_nReadWriteCounter = 0; // writer
    244   else
    245     m_nReadWriteCounter--;
    246 
    247   return nRes;
    248 }
    249 
    250 
    251 DMLockManager::DMLockManager() :
    252   m_oThread( this )
    253 {
    254  m_ptrQueue = NULL;
    255 }
    256 
    257 DMLockManager::~DMLockManager()
    258 {
    259   Destroy();
    260 }
    261 
    262 SYNCML_DM_RET_STATUS_T DMLockManager::Init( CPCHAR szLockFileNamePrefix, INT32 nNumberOfLocks )
    263 {
    264 
    265   nNumberOfLocks += 2; // count for ACL lock as well (the last one) and Evt lock
    266   m_aLocks.set_size( nNumberOfLocks );
    267   if ( m_aLocks.size() != nNumberOfLocks )
    268     {
    269        m_aLocks.clear();
    270        return SYNCML_DM_DEVICE_FULL;
    271     }
    272 
    273   SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS;
    274 
    275   while( nNumberOfLocks-- )
    276   {
    277     char szIndex[10];
    278     DMString strName = szLockFileNamePrefix;
    279     DmSnprintf( szIndex, sizeof(szIndex), "%d", nNumberOfLocks );
    280     strName += szIndex;
    281 
    282     dm_stat = m_aLocks[ nNumberOfLocks ].Init( strName.c_str() );
    283 
    284     if ( dm_stat  != SYNCML_DM_SUCCESS )
    285         return dm_stat;
    286   }
    287 
    288   return dm_stat;
    289 }
    290 
    291 
    292 SYNCML_DM_RET_STATUS_T DMLockManager::StartThread()
    293 {
    294 
    295     if ( m_ptrQueue == NULL )
    296     {
    297         m_ptrQueue = new DMThreadQueue;
    298         if( m_ptrQueue == NULL)
    299             return SYNCML_DM_DEVICE_FULL;
    300 
    301         if ( !m_oThread.StartThread() )
    302             return SYNCML_DM_UNABLE_START_THREAD;
    303 
    304 
    305         INT32 nThreadState;
    306 
    307         while ( (nThreadState = m_oThread.GetThreadState()) == SYNCML_DM_THREAD_STARTING )
    308             DmThSleep( 1000 ); /// give a chance to start
    309 
    310         if ( nThreadState != SYNCML_DM_THREAD_STARTED )
    311         {
    312             Destroy();
    313             return SYNCML_DM_UNABLE_START_THREAD;
    314         }
    315     }
    316 
    317     return SYNCML_DM_SUCCESS;
    318 }
    319 
    320 SYNCML_DM_RET_STATUS_T DMLockManager::Destroy()
    321 {
    322     if(m_ptrQueue != NULL)
    323     {
    324         if ( m_oThread.GetThreadState() == SYNCML_DM_THREAD_STARTED )
    325         {
    326             m_ptrQueue->Post(SYNCML_DM_THREAD_EVENT_TYPE_SHUTDOWN);
    327             m_oThread.StopThread();
    328 
    329         }
    330       m_ptrQueue = NULL;
    331     }
    332 
    333      //release locks
    334 
    335         for( int i = 0; i < m_aLocks.size(); i++ )
    336             m_aLocks[i].Destroy();
    337 
    338         m_aLocks.clear();
    339 
    340 
    341     return SYNCML_DM_SUCCESS;
    342 }
    343 
    344 
    345 SYNCML_DM_RET_STATUS_T DMLockManager::LockSet( FILESETTYPE nLockSet,
    346                                                SYNCML_DM_TREE_LOCK_TYPE_T eLockType )
    347 {
    348 
    349     SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS;
    350 
    351     if  ( eLockType != SYNCML_DM_LOCK_TYPE_SHARED )
    352     {
    353         dm_stat = StartThread();
    354         if ( dm_stat != SYNCML_DM_SUCCESS )
    355         return dm_stat;
    356 
    357         dm_stat = SendAndWait( TRUE, nLockSet, eLockType );
    358     }
    359     else
    360     {
    361         INT32 nNumber = m_aLocks.size();
    362 
    363         for ( int i = 0; i < nNumber; i++ )
    364         {
    365             if ( (1 << i) & nLockSet )
    366             {
    367                 while( m_aLocks[i].Lock( eLockType ) == SYNCML_DM_LOCK_TRY_AGAIN )
    368                     DmThSleep( 1000 );
    369             }
    370         }
    371     }
    372     return dm_stat;
    373 }
    374 
    375 SYNCML_DM_RET_STATUS_T
    376 DMLockManager::UnlockSet( FILESETTYPE nLockSet,
    377                                            SYNCML_DM_TREE_LOCK_TYPE_T eLockType )
    378 {
    379     if ( eLockType != SYNCML_DM_LOCK_TYPE_SHARED )
    380         return SendAndWait( FALSE, nLockSet, 0 );
    381     else
    382     {
    383         INT32 nNumber = m_aLocks.size();
    384 
    385         for ( int i = 0; i < nNumber; i++ )
    386         {
    387             if ( (1 << i) & nLockSet )
    388             {
    389                 m_aLocks[i].Unlock();
    390             }
    391         }
    392         return SYNCML_DM_SUCCESS;
    393     }
    394 }
    395 
    396 SYNCML_DM_RET_STATUS_T DMLockManager::SendAndWait(BOOLEAN bIsLock, FILESETTYPE nLockSet, INT32 eLockType )
    397 {
    398   BOOLEAN bOK = FALSE;
    399 
    400   while ( !bOK ) {
    401     DMFileLockParam* pFileLockMsg = (DMFileLockParam*)DmAllocMem(sizeof(DMFileLockParam) );
    402 
    403     if ( !pFileLockMsg )
    404       return SYNCML_DM_DEVICE_FULL;
    405 
    406     int nStatus = SYNCML_DM_FILE_LOCK_STATUS_IN_PROGRESS;
    407 
    408     pFileLockMsg->m_bIsLock = bIsLock;
    409     pFileLockMsg->m_pDoneFlag = bIsLock ? &nStatus : NULL;
    410     pFileLockMsg->m_eLockType = eLockType;
    411     pFileLockMsg->m_nLockSet = nLockSet;
    412 
    413     if ( !m_ptrQueue->Post( SYNCML_DM_THREAD_EVENT_TYPE_FILELOCK, pFileLockMsg) ) {
    414       DmFreeMem(pFileLockMsg);
    415       return SYNCML_DM_FAIL;
    416     }
    417 
    418     if ( !bIsLock )
    419       break;
    420 
    421     // wait for "done" flag marked
    422     while ( nStatus == SYNCML_DM_FILE_LOCK_STATUS_IN_PROGRESS )
    423       DmThSleep(1000);
    424 
    425     if ( nStatus != SYNCML_DM_FILE_LOCK_STATUS_TRY_AGAIN )
    426       return nStatus == SYNCML_DM_FILE_LOCK_STATUS_OK ? SYNCML_DM_SUCCESS : SYNCML_DM_FAIL;
    427   }
    428 
    429   return SYNCML_DM_SUCCESS;
    430 }
    431 
    432 
    433 BOOLEAN DMLockManager::ProcessLockRequest( DMFileLockParam* pFileLockMsg )
    434 {
    435   INT32 nNumber = m_aLocks.size();
    436   SYNCML_DM_RET_STATUS_T nRes = SYNCML_DM_SUCCESS;
    437 
    438   for ( int i = 0; i < nNumber; i++ ){
    439     if ( (1 << i) & pFileLockMsg->m_nLockSet ) {
    440       if ( !pFileLockMsg->m_bIsLock )
    441       {
    442         nRes = m_aLocks[i].Unlock();
    443       }
    444       else
    445       {
    446         if ( (nRes = m_aLocks[i].Lock( pFileLockMsg->m_eLockType)) == SYNCML_DM_LOCK_TRY_AGAIN )
    447           return FALSE;
    448       }
    449       // mark processed files
    450       pFileLockMsg->m_nLockSet &= ~((FILESETTYPE)((FILESETTYPE)1 << i));
    451     }
    452   }
    453 
    454   if ( pFileLockMsg->m_pDoneFlag )
    455     *(pFileLockMsg->m_pDoneFlag) = (nRes == SYNCML_DM_SUCCESS ? SYNCML_DM_FILE_LOCK_STATUS_OK : SYNCML_DM_FILE_LOCK_STATUS_ERROR);
    456 
    457   return TRUE;
    458 }
    459 
    460 
    461 SYNCML_DM_RET_STATUS_T
    462 DMLockManager::ReleaseFile(SYNCML_DM_FILE_TYPE_T eFileType)
    463 {
    464     if ( eFileType ==  SYNCML_DM_FILE_ACL )
    465         return SendAndWait( FALSE, 1 << (m_aLocks.size()-1), 0 );
    466     else
    467         return SendAndWait( FALSE, 1 << (m_aLocks.size()-2), 0 );
    468 }
    469 
    470 SYNCML_DM_RET_STATUS_T
    471 DMLockManager::AcquireFile(SYNCML_DM_FILE_TYPE_T eFileType )
    472 {
    473     if ( eFileType ==  SYNCML_DM_FILE_ACL )
    474         return LockSet( 1 << (m_aLocks.size()-1), SYNCML_DM_LOCK_TYPE_EXCLUSIVE );
    475     else
    476         return LockSet( 1 << (m_aLocks.size()-2), SYNCML_DM_LOCK_TYPE_EXCLUSIVE );
    477 }
    478 
    479 #endif
    480