Home | History | Annotate | Download | only in utils
      1 /*
      2 * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
      3 *
      4 * Redistribution and use in source and binary forms, with or without modification, are permitted
      5 * provided that the following conditions are met:
      6 *    * Redistributions of source code must retain the above copyright notice, this list of
      7 *      conditions and the following disclaimer.
      8 *    * Redistributions in binary form must reproduce the above copyright notice, this list of
      9 *      conditions and the following disclaimer in the documentation and/or other materials provided
     10 *      with the distribution.
     11 *    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
     12 *      endorse or promote products derived from this software without specific prior written
     13 *      permission.
     14 *
     15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     17 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
     18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     21 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23 */
     24 
     25 #ifndef __LOCKER_H__
     26 #define __LOCKER_H__
     27 
     28 #include <stdint.h>
     29 #include <pthread.h>
     30 #include <sys/time.h>
     31 
     32 #define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker)
     33 #define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker)
     34 #define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker)
     35 #define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker)
     36 #define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker)
     37 
     38 namespace sdm {
     39 
     40 class Locker {
     41  public:
     42   class ScopeLock {
     43    public:
     44     explicit ScopeLock(Locker& locker) : locker_(locker) {
     45       locker_.Lock();
     46     }
     47 
     48     ~ScopeLock() {
     49       locker_.Unlock();
     50     }
     51 
     52    private:
     53     Locker &locker_;
     54   };
     55 
     56   class SequenceEntryScopeLock {
     57    public:
     58     explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) {
     59       locker_.Lock();
     60       locker_.sequence_wait_ = 1;
     61     }
     62 
     63     ~SequenceEntryScopeLock() {
     64       locker_.Unlock();
     65     }
     66 
     67    private:
     68     Locker &locker_;
     69   };
     70 
     71   class SequenceExitScopeLock {
     72    public:
     73     explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) {
     74       locker_.Lock();
     75       locker_.sequence_wait_ = 0;
     76     }
     77 
     78     ~SequenceExitScopeLock() {
     79       locker_.Broadcast();
     80       locker_.Unlock();
     81     }
     82 
     83    private:
     84     Locker &locker_;
     85   };
     86 
     87   class SequenceWaitScopeLock {
     88    public:
     89     explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) {
     90       locker_.Lock();
     91 
     92       while (locker_.sequence_wait_ == 1) {
     93         locker_.Wait();
     94         error_ = (locker_.sequence_wait_ == -1);
     95       }
     96     }
     97 
     98     ~SequenceWaitScopeLock() {
     99       locker_.Unlock();
    100     }
    101 
    102     bool IsError() {
    103       return error_;
    104     }
    105 
    106    private:
    107     Locker &locker_;
    108     bool error_;
    109   };
    110 
    111   class SequenceCancelScopeLock {
    112    public:
    113     explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) {
    114       locker_.Lock();
    115       locker_.sequence_wait_ = -1;
    116     }
    117 
    118     ~SequenceCancelScopeLock() {
    119       locker_.Broadcast();
    120       locker_.Unlock();
    121     }
    122 
    123    private:
    124     Locker &locker_;
    125   };
    126 
    127   Locker() : sequence_wait_(0) {
    128     pthread_mutex_init(&mutex_, 0);
    129     pthread_cond_init(&condition_, 0);
    130   }
    131 
    132   ~Locker() {
    133     pthread_mutex_destroy(&mutex_);
    134     pthread_cond_destroy(&condition_);
    135   }
    136 
    137   void Lock() { pthread_mutex_lock(&mutex_); }
    138   void Unlock() { pthread_mutex_unlock(&mutex_); }
    139   void Signal() { pthread_cond_signal(&condition_); }
    140   void Broadcast() { pthread_cond_broadcast(&condition_); }
    141   void Wait() { pthread_cond_wait(&condition_, &mutex_); }
    142   int WaitFinite(int ms) {
    143     struct timespec ts;
    144     struct timeval tv;
    145     gettimeofday(&tv, NULL);
    146     ts.tv_sec = tv.tv_sec + ms/1000;
    147     ts.tv_nsec = tv.tv_usec*1000 + (ms%1000)*1000000;
    148     ts.tv_sec += ts.tv_nsec/1000000000L;
    149     ts.tv_nsec %= 1000000000L;
    150     return pthread_cond_timedwait(&condition_, &mutex_, &ts);
    151   }
    152 
    153  private:
    154   pthread_mutex_t mutex_;
    155   pthread_cond_t condition_;
    156   int sequence_wait_;   // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
    157                         // Some routines will wait for sequence of function calls to finish
    158                         // so that capturing a transitionary snapshot of context is prevented.
    159                         // If flag is set to -1, these routines will exit without doing any
    160                         // further processing.
    161 };
    162 
    163 }  // namespace sdm
    164 
    165 #endif  // __LOCKER_H__
    166 
    167