1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6
7
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9
10 PerconaFT is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License, version 2,
12 as published by the Free Software Foundation.
13
14 PerconaFT is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
21
22 ----------------------------------------
23
24 PerconaFT is free software: you can redistribute it and/or modify
25 it under the terms of the GNU Affero General Public License, version 3,
26 as published by the Free Software Foundation.
27
28 PerconaFT is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU Affero General Public License for more details.
32
33 You should have received a copy of the GNU Affero General Public License
34 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38
39 #include "test.h"
40
41 // test create and destroy
42
test_create_destroy(void)43 static void test_create_destroy(void) {
44 struct st_rwlock the_rwlock, *rwlock = &the_rwlock;
45
46 rwlock_init(toku_uninstrumented, rwlock);
47 rwlock_destroy(rwlock);
48 }
49
50 // test read lock and unlock with no writers
51
test_simple_read_lock(int n)52 static void test_simple_read_lock(int n) {
53 struct st_rwlock the_rwlock, *rwlock = &the_rwlock;
54
55 rwlock_init(toku_uninstrumented, rwlock);
56 assert(rwlock_readers(rwlock) == 0);
57 int i;
58 for (i = 1; i <= n; i++) {
59 rwlock_read_lock(rwlock, 0);
60 assert(rwlock_readers(rwlock) == i);
61 assert(rwlock_users(rwlock) == i);
62 }
63 for (i=n-1; i>=0; i--) {
64 rwlock_read_unlock(rwlock);
65 assert(rwlock_readers(rwlock) == i);
66 assert(rwlock_users(rwlock) == i);
67 }
68 rwlock_destroy(rwlock);
69 }
70
71 // test write lock and unlock with no readers
72
test_simple_write_lock(void)73 static void test_simple_write_lock(void) {
74 struct st_rwlock the_rwlock, *rwlock = &the_rwlock;
75
76 rwlock_init(toku_uninstrumented, rwlock);
77 assert(rwlock_users(rwlock) == 0);
78 rwlock_write_lock(rwlock, 0);
79 assert(rwlock_writers(rwlock) == 1);
80 assert(rwlock_users(rwlock) == 1);
81 rwlock_write_unlock(rwlock);
82 assert(rwlock_users(rwlock) == 0);
83 rwlock_destroy(rwlock);
84 }
85
86 struct rw_event {
87 int e;
88 struct st_rwlock the_rwlock;
89 toku_mutex_t mutex;
90 };
91
rw_event_init(struct rw_event * rwe)92 static void rw_event_init(struct rw_event *rwe) {
93 rwe->e = 0;
94 rwlock_init(toku_uninstrumented, &rwe->the_rwlock);
95 toku_mutex_init(toku_uninstrumented, &rwe->mutex, nullptr);
96 }
97
rw_event_destroy(struct rw_event * rwe)98 static void rw_event_destroy(struct rw_event *rwe) {
99 rwlock_destroy(&rwe->the_rwlock);
100 toku_mutex_destroy(&rwe->mutex);
101 }
102
103 static void *
test_writer_priority_thread(void * arg)104 test_writer_priority_thread (void *arg) {
105 struct rw_event *CAST_FROM_VOIDP(rwe, arg);
106
107 toku_mutex_lock(&rwe->mutex);
108 rwlock_write_lock(&rwe->the_rwlock, &rwe->mutex);
109 rwe->e++; assert(rwe->e == 3);
110 toku_mutex_unlock(&rwe->mutex);
111 sleep(1);
112 toku_mutex_lock(&rwe->mutex);
113 rwe->e++; assert(rwe->e == 4);
114 rwlock_write_unlock(&rwe->the_rwlock);
115 toku_mutex_unlock(&rwe->mutex);
116
117 return arg;
118 }
119
120 // test writer priority over new readers
121
122 static void
test_writer_priority(void)123 test_writer_priority (void) {
124 struct rw_event rw_event, *rwe = &rw_event;
125 ZERO_STRUCT(rw_event);
126 int r;
127
128 rw_event_init(rwe);
129 toku_mutex_lock(&rwe->mutex);
130 rwlock_read_lock(&rwe->the_rwlock, &rwe->mutex);
131 sleep(1);
132 rwe->e++; assert(rwe->e == 1);
133 toku_mutex_unlock(&rwe->mutex);
134
135 toku_pthread_t tid;
136 r = toku_pthread_create(
137 toku_uninstrumented, &tid, 0, test_writer_priority_thread, rwe);
138 sleep(1);
139 toku_mutex_lock(&rwe->mutex);
140 rwe->e++;
141 assert(rwe->e == 2);
142 toku_mutex_unlock(&rwe->mutex);
143
144 sleep(1);
145 toku_mutex_lock(&rwe->mutex);
146 rwlock_read_unlock(&rwe->the_rwlock);
147 toku_mutex_unlock(&rwe->mutex);
148 sleep(1);
149 toku_mutex_lock(&rwe->mutex);
150 rwlock_read_lock(&rwe->the_rwlock, &rwe->mutex);
151 rwe->e++; assert(rwe->e == 5);
152 toku_mutex_unlock(&rwe->mutex);
153 sleep(1);
154 toku_mutex_lock(&rwe->mutex);
155 rwlock_read_unlock(&rwe->the_rwlock);
156 toku_mutex_unlock(&rwe->mutex);
157
158 void *ret;
159 r = toku_pthread_join(tid, &ret); assert(r == 0);
160
161 rw_event_destroy(rwe);
162 }
163
164 // test single writer
165
166 static void *
test_single_writer_thread(void * arg)167 test_single_writer_thread (void *arg) {
168 struct rw_event *CAST_FROM_VOIDP(rwe, arg);
169
170 toku_mutex_lock(&rwe->mutex);
171 rwlock_write_lock(&rwe->the_rwlock, &rwe->mutex);
172 rwe->e++; assert(rwe->e == 3);
173 assert(rwlock_writers(&rwe->the_rwlock) == 1);
174 rwlock_write_unlock(&rwe->the_rwlock);
175 toku_mutex_unlock(&rwe->mutex);
176
177 return arg;
178 }
179
180 static void
test_single_writer(void)181 test_single_writer (void) {
182 struct rw_event rw_event, *rwe = &rw_event;
183 ZERO_STRUCT(rw_event);
184 int r;
185
186 rw_event_init(rwe);
187 assert(rwlock_writers(&rwe->the_rwlock) == 0);
188 toku_mutex_lock(&rwe->mutex);
189 rwlock_write_lock(&rwe->the_rwlock, &rwe->mutex);
190 assert(rwlock_writers(&rwe->the_rwlock) == 1);
191 sleep(1);
192 rwe->e++; assert(rwe->e == 1);
193 toku_mutex_unlock(&rwe->mutex);
194
195 toku_pthread_t tid;
196 r = toku_pthread_create(
197 toku_uninstrumented, &tid, 0, test_single_writer_thread, rwe);
198 sleep(1);
199 toku_mutex_lock(&rwe->mutex);
200 rwe->e++;
201 assert(rwe->e == 2);
202 assert(rwlock_writers(&rwe->the_rwlock) == 1);
203 assert(rwlock_users(&rwe->the_rwlock) == 2);
204 rwlock_write_unlock(&rwe->the_rwlock);
205 toku_mutex_unlock(&rwe->mutex);
206
207 void *ret;
208 r = toku_pthread_join(tid, &ret); assert(r == 0);
209
210 assert(rwlock_writers(&rwe->the_rwlock) == 0);
211 rw_event_destroy(rwe);
212 }
213
214 int
test_main(int argc,const char * argv[])215 test_main(int argc, const char *argv[]) {
216 default_parse_args(argc, argv);
217 test_create_destroy();
218 test_simple_read_lock(0);
219 test_simple_read_lock(42);
220 test_simple_write_lock();
221 test_writer_priority();
222 test_single_writer();
223
224 return 0;
225 }
226