summaryrefslogtreecommitdiffstats
path: root/src/common/Cond.h
blob: f41d0bf40702e98d1061836b6cbd0393982176f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */


#ifndef CEPH_COND_H
#define CEPH_COND_H

#include "common/Clock.h"
#include "common/ceph_mutex.h"
#include "include/Context.h"

/**
 * context to signal a cond
 *
 * Generic context to signal a cond and store the return value.  We
 * assume the caller is holding the appropriate lock.
 */
class C_Cond : public Context {
  ceph::condition_variable& cond;   ///< Cond to signal
  bool *done;   ///< true if finish() has been called
  int *rval;    ///< return value
public:
  C_Cond(ceph::condition_variable &c, bool *d, int *r) : cond(c), done(d), rval(r) {
    *done = false;
  }
  void finish(int r) override {
    *done = true;
    *rval = r;
    cond.notify_all();
  }
};

/**
 * context to signal a cond, protected by a lock
 *
 * Generic context to signal a cond under a specific lock. We take the
 * lock in the finish() callback, so the finish() caller must not
 * already hold it.
 */
class C_SafeCond : public Context {
  ceph::mutex& lock;    ///< Mutex to take
  ceph::condition_variable& cond;     ///< Cond to signal
  bool *done;     ///< true after finish() has been called
  int *rval;      ///< return value (optional)
public:
  C_SafeCond(ceph::mutex& l, ceph::condition_variable& c, bool *d, int *r=0)
    : lock(l), cond(c), done(d), rval(r) {
    *done = false;
  }
  void finish(int r) override {
    std::lock_guard l{lock};
    if (rval)
      *rval = r;
    *done = true;
    cond.notify_all();
  }
};

/**
 * Context providing a simple wait() mechanism to wait for completion
 *
 * The context will not be deleted as part of complete and must live
 * until wait() returns.
 */
class C_SaferCond : public Context {
  ceph::mutex lock;  ///< Mutex to take
  ceph::condition_variable cond;     ///< Cond to signal
  bool done = false; ///< true after finish() has been called
  int rval = 0;      ///< return value
public:
  C_SaferCond() :
    C_SaferCond("C_SaferCond")
  {}
  explicit C_SaferCond(const std::string &name)
    : lock(ceph::make_mutex(name)) {}
  void finish(int r) override { complete(r); }

  /// We overload complete in order to not delete the context
  void complete(int r) override {
    std::lock_guard l(lock);
    done = true;
    rval = r;
    cond.notify_all();
  }

  /// Returns rval once the Context is called
  int wait() {
    std::unique_lock l{lock};
    cond.wait(l, [this] { return done;});
    return rval;
  }

  /// Wait until the \c secs expires or \c complete() is called
  int wait_for(double secs) {
    return wait_for(ceph::make_timespan(secs));
  }

  int wait_for(ceph::timespan secs) {
    std::unique_lock l{lock};
    if (done) {
      return rval;
    }
    if (cond.wait_for(l, secs, [this] { return done; })) {
      return rval;
    } else {
      return ETIMEDOUT;
    }
  }
};

#endif