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
38namespace sdm {
39
40class 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