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