Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / common / Cond.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15
16 #ifndef CEPH_COND_H
17 #define CEPH_COND_H
18
19 #include "include/Context.h"
20
21 class Cond {
22   // my bits
23   pthread_cond_t _c;
24
25   Mutex *waiter_mutex;
26
27   // don't allow copying.
28   void operator=(Cond &C);
29   Cond(const Cond &C);
30
31  public:
32   Cond() : waiter_mutex(NULL) {
33     int r = pthread_cond_init(&_c,NULL);
34     assert(r == 0);
35   }
36   virtual ~Cond() { 
37     pthread_cond_destroy(&_c); 
38   }
39
40   int Wait(Mutex &mutex)  { 
41     // make sure this cond is used with one mutex only
42     assert(waiter_mutex == NULL || waiter_mutex == &mutex);
43     waiter_mutex = &mutex;
44
45     assert(mutex.is_locked());
46
47     mutex._pre_unlock();
48     int r = pthread_cond_wait(&_c, &mutex._m);
49     mutex._post_lock();
50     return r;
51   }
52
53   int WaitUntil(Mutex &mutex, utime_t when) {
54     // make sure this cond is used with one mutex only
55     assert(waiter_mutex == NULL || waiter_mutex == &mutex);
56     waiter_mutex = &mutex;
57
58     assert(mutex.is_locked());
59
60     struct timespec ts;
61     when.to_timespec(&ts);
62
63     mutex._pre_unlock();
64     int r = pthread_cond_timedwait(&_c, &mutex._m, &ts);
65     mutex._post_lock();
66
67     return r;
68   }
69
70   int WaitInterval(Mutex &mutex, utime_t interval) {
71     utime_t when = ceph_clock_now();
72     when += interval;
73     return WaitUntil(mutex, when);
74   }
75
76   template<typename Duration>
77   int WaitInterval(Mutex &mutex, Duration interval) {
78     ceph::real_time when(ceph::real_clock::now());
79     when += interval;
80
81     struct timespec ts = ceph::real_clock::to_timespec(when);
82
83     mutex._pre_unlock();
84     int r = pthread_cond_timedwait(&_c, &mutex._m, &ts);
85     mutex._post_lock();
86
87     return r;
88   }
89
90   int SloppySignal() { 
91     int r = pthread_cond_broadcast(&_c);
92     return r;
93   }
94   int Signal() { 
95     // make sure signaler is holding the waiter's lock.
96     assert(waiter_mutex == NULL ||
97            waiter_mutex->is_locked());
98
99     int r = pthread_cond_broadcast(&_c);
100     return r;
101   }
102   int SignalOne() { 
103     // make sure signaler is holding the waiter's lock.
104     assert(waiter_mutex == NULL ||
105            waiter_mutex->is_locked());
106
107     int r = pthread_cond_signal(&_c);
108     return r;
109   }
110   int SignalAll() { 
111     // make sure signaler is holding the waiter's lock.
112     assert(waiter_mutex == NULL ||
113            waiter_mutex->is_locked());
114
115     int r = pthread_cond_broadcast(&_c);
116     return r;
117   }
118 };
119
120 /**
121  * context to signal a cond
122  *
123  * Generic context to signal a cond and store the return value.  We
124  * assume the caller is holding the appropriate lock.
125  */
126 class C_Cond : public Context {
127   Cond *cond;   ///< Cond to signal
128   bool *done;   ///< true if finish() has been called
129   int *rval;    ///< return value
130 public:
131   C_Cond(Cond *c, bool *d, int *r) : cond(c), done(d), rval(r) {
132     *done = false;
133   }
134   void finish(int r) override {
135     *done = true;
136     *rval = r;
137     cond->Signal();
138   }
139 };
140
141 /**
142  * context to signal a cond, protected by a lock
143  *
144  * Generic context to signal a cond under a specific lock. We take the
145  * lock in the finish() callback, so the finish() caller must not
146  * already hold it.
147  */
148 class C_SafeCond : public Context {
149   Mutex *lock;    ///< Mutex to take
150   Cond *cond;     ///< Cond to signal
151   bool *done;     ///< true after finish() has been called
152   int *rval;      ///< return value (optional)
153 public:
154   C_SafeCond(Mutex *l, Cond *c, bool *d, int *r=0) : lock(l), cond(c), done(d), rval(r) {
155     *done = false;
156   }
157   void finish(int r) override {
158     lock->Lock();
159     if (rval)
160       *rval = r;
161     *done = true;
162     cond->Signal();
163     lock->Unlock();
164   }
165 };
166
167 /**
168  * Context providing a simple wait() mechanism to wait for completion
169  *
170  * The context will not be deleted as part of complete and must live
171  * until wait() returns.
172  */
173 class C_SaferCond : public Context {
174   Mutex lock;    ///< Mutex to take
175   Cond cond;     ///< Cond to signal
176   bool done;     ///< true after finish() has been called
177   int rval;      ///< return value
178 public:
179   C_SaferCond() : lock("C_SaferCond"), done(false), rval(0) {}
180   void finish(int r) override { complete(r); }
181
182   /// We overload complete in order to not delete the context
183   void complete(int r) override {
184     Mutex::Locker l(lock);
185     done = true;
186     rval = r;
187     cond.Signal();
188   }
189
190   /// Returns rval once the Context is called
191   int wait() {
192     Mutex::Locker l(lock);
193     while (!done)
194       cond.Wait(lock);
195     return rval;
196   }
197 };
198
199 #endif