1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// UNSUPPORTED: libcpp-has-no-threads
11// UNSUPPORTED: c++98, c++03
12
13// <mutex>
14
15// template <class ...Mutex> class lock_guard;
16
17// explicit lock_guard(mutex_type& m);
18
19// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
20#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
21#include <mutex>
22#include <cassert>
23
24#include "test_macros.h"
25
26struct TestMutex {
27    bool locked = false;
28    TestMutex() = default;
29    ~TestMutex() { assert(!locked); }
30
31    void lock() { assert(!locked); locked = true; }
32    bool try_lock() { if (locked) return false; locked = true; return true; }
33    void unlock() { assert(locked); locked = false; }
34
35    TestMutex(TestMutex const&) = delete;
36    TestMutex& operator=(TestMutex const&) = delete;
37};
38
39#if !defined(TEST_HAS_NO_EXCEPTIONS)
40struct TestMutexThrows {
41    bool locked = false;
42    bool throws_on_lock = false;
43
44    TestMutexThrows() = default;
45    ~TestMutexThrows() { assert(!locked); }
46
47    void lock() {
48        assert(!locked);
49        if (throws_on_lock) {
50            throw 42;
51        }
52        locked = true;
53    }
54
55    bool try_lock() {
56        if (locked) return false;
57        lock();
58        return true;
59    }
60
61    void unlock() { assert(locked); locked = false; }
62
63    TestMutexThrows(TestMutexThrows const&) = delete;
64    TestMutexThrows& operator=(TestMutexThrows const&) = delete;
65};
66#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
67
68int main()
69{
70    {
71        using LG = std::lock_guard<>;
72        LG lg;
73    }
74    {
75        using LG = std::lock_guard<TestMutex, TestMutex>;
76        TestMutex m1, m2;
77        {
78            LG lg(m1, m2);
79            assert(m1.locked && m2.locked);
80        }
81        assert(!m1.locked && !m2.locked);
82    }
83    {
84        using LG = std::lock_guard<TestMutex, TestMutex, TestMutex>;
85        TestMutex m1, m2, m3;
86        {
87            LG lg(m1, m2, m3);
88            assert(m1.locked && m2.locked && m3.locked);
89        }
90        assert(!m1.locked && !m2.locked && !m3.locked);
91    }
92#if !defined(TEST_HAS_NO_EXCEPTIONS)
93    {
94        using MT = TestMutexThrows;
95        using LG = std::lock_guard<MT, MT>;
96        MT m1, m2;
97        m1.throws_on_lock = true;
98        try {
99            LG lg(m1, m2);
100            assert(false);
101        } catch (int) {}
102        assert(!m1.locked && !m2.locked);
103    }
104    {
105        using MT = TestMutexThrows;
106        using LG = std::lock_guard<MT, MT, MT>;
107        MT m1, m2, m3;
108        m2.throws_on_lock = true;
109        try {
110            LG lg(m1, m2, m3);
111            assert(false);
112        } catch (int) {}
113        assert(!m1.locked && !m2.locked && !m3.locked);
114    }
115#endif
116}
117